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 '<div name="{id}">',
4405 '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
4408 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4410 * 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>.
4412 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4414 Roo.Template = function(html){
4415 if(html instanceof Array){
4416 html = html.join("");
4417 }else if(arguments.length > 1){
4418 html = Array.prototype.join.call(arguments, "");
4424 Roo.Template.prototype = {
4426 * Returns an HTML fragment of this template with the specified values applied.
4427 * @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'})
4428 * @return {String} The HTML fragment
4430 applyTemplate : function(values){
4434 return this.compiled(values);
4436 var useF = this.disableFormats !== true;
4437 var fm = Roo.util.Format, tpl = this;
4438 var fn = function(m, name, format, args){
4440 if(format.substr(0, 5) == "this."){
4441 return tpl.call(format.substr(5), values[name], values);
4444 // quoted values are required for strings in compiled templates,
4445 // but for non compiled we need to strip them
4446 // quoted reversed for jsmin
4447 var re = /^\s*['"](.*)["']\s*$/;
4448 args = args.split(',');
4449 for(var i = 0, len = args.length; i < len; i++){
4450 args[i] = args[i].replace(re, "$1");
4452 args = [values[name]].concat(args);
4454 args = [values[name]];
4456 return fm[format].apply(fm, args);
4459 return values[name] !== undefined ? values[name] : "";
4462 return this.html.replace(this.re, fn);
4471 * Sets the HTML used as the template and optionally compiles it.
4472 * @param {String} html
4473 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4474 * @return {Roo.Template} this
4476 set : function(html, compile){
4478 this.compiled = null;
4486 * True to disable format functions (defaults to false)
4489 disableFormats : false,
4492 * The regular expression used to match template variables
4496 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4499 * Compiles the template into an internal function, eliminating the RegEx overhead.
4500 * @return {Roo.Template} this
4502 compile : function(){
4503 var fm = Roo.util.Format;
4504 var useF = this.disableFormats !== true;
4505 var sep = Roo.isGecko ? "+" : ",";
4506 var fn = function(m, name, format, args){
4508 args = args ? ',' + args : "";
4509 if(format.substr(0, 5) != "this."){
4510 format = "fm." + format + '(';
4512 format = 'this.call("'+ format.substr(5) + '", ';
4516 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4518 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4521 // branched to use + in gecko and [].join() in others
4523 body = "this.compiled = function(values){ return '" +
4524 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4527 body = ["this.compiled = function(values){ return ['"];
4528 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4529 body.push("'].join('');};");
4530 body = body.join('');
4540 // private function used to call members
4541 call : function(fnName, value, allValues){
4542 return this[fnName](value, allValues);
4546 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4547 * @param {String/HTMLElement/Roo.Element} el The context element
4548 * @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'})
4549 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4550 * @return {HTMLElement/Roo.Element} The new node or Element
4552 insertFirst: function(el, values, returnElement){
4553 return this.doInsert('afterBegin', el, values, returnElement);
4557 * Applies the supplied values to the template and inserts the new node(s) before el.
4558 * @param {String/HTMLElement/Roo.Element} el The context element
4559 * @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'})
4560 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4561 * @return {HTMLElement/Roo.Element} The new node or Element
4563 insertBefore: function(el, values, returnElement){
4564 return this.doInsert('beforeBegin', el, values, returnElement);
4568 * Applies the supplied values to the template and inserts the new node(s) after el.
4569 * @param {String/HTMLElement/Roo.Element} el The context element
4570 * @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'})
4571 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4572 * @return {HTMLElement/Roo.Element} The new node or Element
4574 insertAfter : function(el, values, returnElement){
4575 return this.doInsert('afterEnd', el, values, returnElement);
4579 * Applies the supplied values to the template and appends the new node(s) to el.
4580 * @param {String/HTMLElement/Roo.Element} el The context element
4581 * @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'})
4582 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4583 * @return {HTMLElement/Roo.Element} The new node or Element
4585 append : function(el, values, returnElement){
4586 return this.doInsert('beforeEnd', el, values, returnElement);
4589 doInsert : function(where, el, values, returnEl){
4590 el = Roo.getDom(el);
4591 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4592 return returnEl ? Roo.get(newNode, true) : newNode;
4596 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4597 * @param {String/HTMLElement/Roo.Element} el The context element
4598 * @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'})
4599 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4600 * @return {HTMLElement/Roo.Element} The new node or Element
4602 overwrite : function(el, values, returnElement){
4603 el = Roo.getDom(el);
4604 el.innerHTML = this.applyTemplate(values);
4605 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4609 * Alias for {@link #applyTemplate}
4612 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4615 Roo.DomHelper.Template = Roo.Template;
4618 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4619 * @param {String/HTMLElement} el A DOM element or its id
4620 * @returns {Roo.Template} The created template
4623 Roo.Template.from = function(el){
4624 el = Roo.getDom(el);
4625 return new Roo.Template(el.value || el.innerHTML);
4628 * Ext JS Library 1.1.1
4629 * Copyright(c) 2006-2007, Ext JS, LLC.
4631 * Originally Released Under LGPL - original licence link has changed is not relivant.
4634 * <script type="text/javascript">
4639 * This is code is also distributed under MIT license for use
4640 * with jQuery and prototype JavaScript libraries.
4643 * @class Roo.DomQuery
4644 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).
4646 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>
4649 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.
4651 <h4>Element Selectors:</h4>
4653 <li> <b>*</b> any element</li>
4654 <li> <b>E</b> an element with the tag E</li>
4655 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4656 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4657 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4658 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4660 <h4>Attribute Selectors:</h4>
4661 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4663 <li> <b>E[foo]</b> has an attribute "foo"</li>
4664 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4665 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4666 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4667 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4668 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4669 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4671 <h4>Pseudo Classes:</h4>
4673 <li> <b>E:first-child</b> E is the first child of its parent</li>
4674 <li> <b>E:last-child</b> E is the last child of its parent</li>
4675 <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>
4676 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4677 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4678 <li> <b>E:only-child</b> E is the only child of its parent</li>
4679 <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>
4680 <li> <b>E:first</b> the first E in the resultset</li>
4681 <li> <b>E:last</b> the last E in the resultset</li>
4682 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4683 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4684 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4685 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4686 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4687 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4688 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4689 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4690 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4692 <h4>CSS Value Selectors:</h4>
4694 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4695 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4696 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4697 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4698 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4699 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4703 Roo.DomQuery = function(){
4704 var cache = {}, simpleCache = {}, valueCache = {};
4705 var nonSpace = /\S/;
4706 var trimRe = /^\s+|\s+$/g;
4707 var tplRe = /\{(\d+)\}/g;
4708 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4709 var tagTokenRe = /^(#)?([\w-\*]+)/;
4710 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4712 function child(p, index){
4714 var n = p.firstChild;
4716 if(n.nodeType == 1){
4727 while((n = n.nextSibling) && n.nodeType != 1);
4732 while((n = n.previousSibling) && n.nodeType != 1);
4736 function children(d){
4737 var n = d.firstChild, ni = -1;
4739 var nx = n.nextSibling;
4740 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4750 function byClassName(c, a, v){
4754 var r = [], ri = -1, cn;
4755 for(var i = 0, ci; ci = c[i]; i++){
4756 if((' '+ci.className+' ').indexOf(v) != -1){
4763 function attrValue(n, attr){
4764 if(!n.tagName && typeof n.length != "undefined"){
4773 if(attr == "class" || attr == "className"){
4776 return n.getAttribute(attr) || n[attr];
4780 function getNodes(ns, mode, tagName){
4781 var result = [], ri = -1, cs;
4785 tagName = tagName || "*";
4786 if(typeof ns.getElementsByTagName != "undefined"){
4790 for(var i = 0, ni; ni = ns[i]; i++){
4791 cs = ni.getElementsByTagName(tagName);
4792 for(var j = 0, ci; ci = cs[j]; j++){
4796 }else if(mode == "/" || mode == ">"){
4797 var utag = tagName.toUpperCase();
4798 for(var i = 0, ni, cn; ni = ns[i]; i++){
4799 cn = ni.children || ni.childNodes;
4800 for(var j = 0, cj; cj = cn[j]; j++){
4801 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4806 }else if(mode == "+"){
4807 var utag = tagName.toUpperCase();
4808 for(var i = 0, n; n = ns[i]; i++){
4809 while((n = n.nextSibling) && n.nodeType != 1);
4810 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4814 }else if(mode == "~"){
4815 for(var i = 0, n; n = ns[i]; i++){
4816 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4825 function concat(a, b){
4829 for(var i = 0, l = b.length; i < l; i++){
4835 function byTag(cs, tagName){
4836 if(cs.tagName || cs == document){
4842 var r = [], ri = -1;
4843 tagName = tagName.toLowerCase();
4844 for(var i = 0, ci; ci = cs[i]; i++){
4845 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4852 function byId(cs, attr, id){
4853 if(cs.tagName || cs == document){
4859 var r = [], ri = -1;
4860 for(var i = 0,ci; ci = cs[i]; i++){
4861 if(ci && ci.id == id){
4869 function byAttribute(cs, attr, value, op, custom){
4870 var r = [], ri = -1, st = custom=="{";
4871 var f = Roo.DomQuery.operators[op];
4872 for(var i = 0, ci; ci = cs[i]; i++){
4875 a = Roo.DomQuery.getStyle(ci, attr);
4877 else if(attr == "class" || attr == "className"){
4879 }else if(attr == "for"){
4881 }else if(attr == "href"){
4882 a = ci.getAttribute("href", 2);
4884 a = ci.getAttribute(attr);
4886 if((f && f(a, value)) || (!f && a)){
4893 function byPseudo(cs, name, value){
4894 return Roo.DomQuery.pseudos[name](cs, value);
4897 // This is for IE MSXML which does not support expandos.
4898 // IE runs the same speed using setAttribute, however FF slows way down
4899 // and Safari completely fails so they need to continue to use expandos.
4900 var isIE = window.ActiveXObject ? true : false;
4902 // this eval is stop the compressor from
4903 // renaming the variable to something shorter
4905 /** eval:var:batch */
4910 function nodupIEXml(cs){
4912 cs[0].setAttribute("_nodup", d);
4914 for(var i = 1, len = cs.length; i < len; i++){
4916 if(!c.getAttribute("_nodup") != d){
4917 c.setAttribute("_nodup", d);
4921 for(var i = 0, len = cs.length; i < len; i++){
4922 cs[i].removeAttribute("_nodup");
4931 var len = cs.length, c, i, r = cs, cj, ri = -1;
4932 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4935 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4936 return nodupIEXml(cs);
4940 for(i = 1; c = cs[i]; i++){
4945 for(var j = 0; j < i; j++){
4948 for(j = i+1; cj = cs[j]; j++){
4960 function quickDiffIEXml(c1, c2){
4962 for(var i = 0, len = c1.length; i < len; i++){
4963 c1[i].setAttribute("_qdiff", d);
4966 for(var i = 0, len = c2.length; i < len; i++){
4967 if(c2[i].getAttribute("_qdiff") != d){
4968 r[r.length] = c2[i];
4971 for(var i = 0, len = c1.length; i < len; i++){
4972 c1[i].removeAttribute("_qdiff");
4977 function quickDiff(c1, c2){
4978 var len1 = c1.length;
4982 if(isIE && c1[0].selectSingleNode){
4983 return quickDiffIEXml(c1, c2);
4986 for(var i = 0; i < len1; i++){
4990 for(var i = 0, len = c2.length; i < len; i++){
4991 if(c2[i]._qdiff != d){
4992 r[r.length] = c2[i];
4998 function quickId(ns, mode, root, id){
5000 var d = root.ownerDocument || root;
5001 return d.getElementById(id);
5003 ns = getNodes(ns, mode, "*");
5004 return byId(ns, null, id);
5008 getStyle : function(el, name){
5009 return Roo.fly(el).getStyle(name);
5012 * Compiles a selector/xpath query into a reusable function. The returned function
5013 * takes one parameter "root" (optional), which is the context node from where the query should start.
5014 * @param {String} selector The selector/xpath query
5015 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5016 * @return {Function}
5018 compile : function(path, type){
5019 type = type || "select";
5021 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5022 var q = path, mode, lq;
5023 var tk = Roo.DomQuery.matchers;
5024 var tklen = tk.length;
5027 // accept leading mode switch
5028 var lmode = q.match(modeRe);
5029 if(lmode && lmode[1]){
5030 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5031 q = q.replace(lmode[1], "");
5033 // strip leading slashes
5034 while(path.substr(0, 1)=="/"){
5035 path = path.substr(1);
5038 while(q && lq != q){
5040 var tm = q.match(tagTokenRe);
5041 if(type == "select"){
5044 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5046 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5048 q = q.replace(tm[0], "");
5049 }else if(q.substr(0, 1) != '@'){
5050 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5055 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5057 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5059 q = q.replace(tm[0], "");
5062 while(!(mm = q.match(modeRe))){
5063 var matched = false;
5064 for(var j = 0; j < tklen; j++){
5066 var m = q.match(t.re);
5068 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5071 q = q.replace(m[0], "");
5076 // prevent infinite loop on bad selector
5078 throw 'Error parsing selector, parsing failed at "' + q + '"';
5082 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5083 q = q.replace(mm[1], "");
5086 fn[fn.length] = "return nodup(n);\n}";
5089 * list of variables that need from compression as they are used by eval.
5099 * eval:var:byClassName
5101 * eval:var:byAttribute
5102 * eval:var:attrValue
5110 * Selects a group of elements.
5111 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5112 * @param {Node} root (optional) The start of the query (defaults to document).
5115 select : function(path, root, type){
5116 if(!root || root == document){
5119 if(typeof root == "string"){
5120 root = document.getElementById(root);
5122 var paths = path.split(",");
5124 for(var i = 0, len = paths.length; i < len; i++){
5125 var p = paths[i].replace(trimRe, "");
5127 cache[p] = Roo.DomQuery.compile(p);
5129 throw p + " is not a valid selector";
5132 var result = cache[p](root);
5133 if(result && result != document){
5134 results = results.concat(result);
5137 if(paths.length > 1){
5138 return nodup(results);
5144 * Selects a single element.
5145 * @param {String} selector The selector/xpath query
5146 * @param {Node} root (optional) The start of the query (defaults to document).
5149 selectNode : function(path, root){
5150 return Roo.DomQuery.select(path, root)[0];
5154 * Selects the value of a node, optionally replacing null with the defaultValue.
5155 * @param {String} selector The selector/xpath query
5156 * @param {Node} root (optional) The start of the query (defaults to document).
5157 * @param {String} defaultValue
5159 selectValue : function(path, root, defaultValue){
5160 path = path.replace(trimRe, "");
5161 if(!valueCache[path]){
5162 valueCache[path] = Roo.DomQuery.compile(path, "select");
5164 var n = valueCache[path](root);
5165 n = n[0] ? n[0] : n;
5166 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5167 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5171 * Selects the value of a node, parsing integers and floats.
5172 * @param {String} selector The selector/xpath query
5173 * @param {Node} root (optional) The start of the query (defaults to document).
5174 * @param {Number} defaultValue
5177 selectNumber : function(path, root, defaultValue){
5178 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5179 return parseFloat(v);
5183 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5184 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5185 * @param {String} selector The simple selector to test
5188 is : function(el, ss){
5189 if(typeof el == "string"){
5190 el = document.getElementById(el);
5192 var isArray = (el instanceof Array);
5193 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5194 return isArray ? (result.length == el.length) : (result.length > 0);
5198 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5199 * @param {Array} el An array of elements to filter
5200 * @param {String} selector The simple selector to test
5201 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5202 * the selector instead of the ones that match
5205 filter : function(els, ss, nonMatches){
5206 ss = ss.replace(trimRe, "");
5207 if(!simpleCache[ss]){
5208 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5210 var result = simpleCache[ss](els);
5211 return nonMatches ? quickDiff(result, els) : result;
5215 * Collection of matching regular expressions and code snippets.
5219 select: 'n = byClassName(n, null, " {1} ");'
5221 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5222 select: 'n = byPseudo(n, "{1}", "{2}");'
5224 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5225 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5228 select: 'n = byId(n, null, "{1}");'
5231 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5236 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5237 * 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, > <.
5240 "=" : function(a, v){
5243 "!=" : function(a, v){
5246 "^=" : function(a, v){
5247 return a && a.substr(0, v.length) == v;
5249 "$=" : function(a, v){
5250 return a && a.substr(a.length-v.length) == v;
5252 "*=" : function(a, v){
5253 return a && a.indexOf(v) !== -1;
5255 "%=" : function(a, v){
5256 return (a % v) == 0;
5258 "|=" : function(a, v){
5259 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5261 "~=" : function(a, v){
5262 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5267 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5268 * and the argument (if any) supplied in the selector.
5271 "first-child" : function(c){
5272 var r = [], ri = -1, n;
5273 for(var i = 0, ci; ci = n = c[i]; i++){
5274 while((n = n.previousSibling) && n.nodeType != 1);
5282 "last-child" : function(c){
5283 var r = [], ri = -1, n;
5284 for(var i = 0, ci; ci = n = c[i]; i++){
5285 while((n = n.nextSibling) && n.nodeType != 1);
5293 "nth-child" : function(c, a) {
5294 var r = [], ri = -1;
5295 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5296 var f = (m[1] || 1) - 0, l = m[2] - 0;
5297 for(var i = 0, n; n = c[i]; i++){
5298 var pn = n.parentNode;
5299 if (batch != pn._batch) {
5301 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5302 if(cn.nodeType == 1){
5309 if (l == 0 || n.nodeIndex == l){
5312 } else if ((n.nodeIndex + l) % f == 0){
5320 "only-child" : function(c){
5321 var r = [], ri = -1;;
5322 for(var i = 0, ci; ci = c[i]; i++){
5323 if(!prev(ci) && !next(ci)){
5330 "empty" : function(c){
5331 var r = [], ri = -1;
5332 for(var i = 0, ci; ci = c[i]; i++){
5333 var cns = ci.childNodes, j = 0, cn, empty = true;
5336 if(cn.nodeType == 1 || cn.nodeType == 3){
5348 "contains" : function(c, v){
5349 var r = [], ri = -1;
5350 for(var i = 0, ci; ci = c[i]; i++){
5351 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5358 "nodeValue" : function(c, v){
5359 var r = [], ri = -1;
5360 for(var i = 0, ci; ci = c[i]; i++){
5361 if(ci.firstChild && ci.firstChild.nodeValue == v){
5368 "checked" : function(c){
5369 var r = [], ri = -1;
5370 for(var i = 0, ci; ci = c[i]; i++){
5371 if(ci.checked == true){
5378 "not" : function(c, ss){
5379 return Roo.DomQuery.filter(c, ss, true);
5382 "odd" : function(c){
5383 return this["nth-child"](c, "odd");
5386 "even" : function(c){
5387 return this["nth-child"](c, "even");
5390 "nth" : function(c, a){
5391 return c[a-1] || [];
5394 "first" : function(c){
5398 "last" : function(c){
5399 return c[c.length-1] || [];
5402 "has" : function(c, ss){
5403 var s = Roo.DomQuery.select;
5404 var r = [], ri = -1;
5405 for(var i = 0, ci; ci = c[i]; i++){
5406 if(s(ss, ci).length > 0){
5413 "next" : function(c, ss){
5414 var is = Roo.DomQuery.is;
5415 var r = [], ri = -1;
5416 for(var i = 0, ci; ci = c[i]; i++){
5425 "prev" : function(c, ss){
5426 var is = Roo.DomQuery.is;
5427 var r = [], ri = -1;
5428 for(var i = 0, ci; ci = c[i]; i++){
5441 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5442 * @param {String} path The selector/xpath query
5443 * @param {Node} root (optional) The start of the query (defaults to document).
5448 Roo.query = Roo.DomQuery.select;
5451 * Ext JS Library 1.1.1
5452 * Copyright(c) 2006-2007, Ext JS, LLC.
5454 * Originally Released Under LGPL - original licence link has changed is not relivant.
5457 * <script type="text/javascript">
5461 * @class Roo.util.Observable
5462 * Base class that provides a common interface for publishing events. Subclasses are expected to
5463 * to have a property "events" with all the events defined.<br>
5466 Employee = function(name){
5473 Roo.extend(Employee, Roo.util.Observable);
5475 * @param {Object} config properties to use (incuding events / listeners)
5478 Roo.util.Observable = function(cfg){
5481 this.addEvents(cfg.events || {});
5483 delete cfg.events; // make sure
5486 Roo.apply(this, cfg);
5489 this.on(this.listeners);
5490 delete this.listeners;
5493 Roo.util.Observable.prototype = {
5495 * @cfg {Object} listeners list of events and functions to call for this object,
5499 'click' : function(e) {
5509 * Fires the specified event with the passed parameters (minus the event name).
5510 * @param {String} eventName
5511 * @param {Object...} args Variable number of parameters are passed to handlers
5512 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5514 fireEvent : function(){
5515 var ce = this.events[arguments[0].toLowerCase()];
5516 if(typeof ce == "object"){
5517 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5524 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5527 * Appends an event handler to this component
5528 * @param {String} eventName The type of event to listen for
5529 * @param {Function} handler The method the event invokes
5530 * @param {Object} scope (optional) The scope in which to execute the handler
5531 * function. The handler function's "this" context.
5532 * @param {Object} options (optional) An object containing handler configuration
5533 * properties. This may contain any of the following properties:<ul>
5534 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5535 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5536 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5537 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5538 * by the specified number of milliseconds. If the event fires again within that time, the original
5539 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5542 * <b>Combining Options</b><br>
5543 * Using the options argument, it is possible to combine different types of listeners:<br>
5545 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5547 el.on('click', this.onClick, this, {
5554 * <b>Attaching multiple handlers in 1 call</b><br>
5555 * The method also allows for a single argument to be passed which is a config object containing properties
5556 * which specify multiple handlers.
5565 fn: this.onMouseOver,
5569 fn: this.onMouseOut,
5575 * Or a shorthand syntax which passes the same scope object to all handlers:
5578 'click': this.onClick,
5579 'mouseover': this.onMouseOver,
5580 'mouseout': this.onMouseOut,
5585 addListener : function(eventName, fn, scope, o){
5586 if(typeof eventName == "object"){
5589 if(this.filterOptRe.test(e)){
5592 if(typeof o[e] == "function"){
5594 this.addListener(e, o[e], o.scope, o);
5596 // individual options
5597 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5602 o = (!o || typeof o == "boolean") ? {} : o;
5603 eventName = eventName.toLowerCase();
5604 var ce = this.events[eventName] || true;
5605 if(typeof ce == "boolean"){
5606 ce = new Roo.util.Event(this, eventName);
5607 this.events[eventName] = ce;
5609 ce.addListener(fn, scope, o);
5613 * Removes a listener
5614 * @param {String} eventName The type of event to listen for
5615 * @param {Function} handler The handler to remove
5616 * @param {Object} scope (optional) The scope (this object) for the handler
5618 removeListener : function(eventName, fn, scope){
5619 var ce = this.events[eventName.toLowerCase()];
5620 if(typeof ce == "object"){
5621 ce.removeListener(fn, scope);
5626 * Removes all listeners for this object
5628 purgeListeners : function(){
5629 for(var evt in this.events){
5630 if(typeof this.events[evt] == "object"){
5631 this.events[evt].clearListeners();
5636 relayEvents : function(o, events){
5637 var createHandler = function(ename){
5639 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5642 for(var i = 0, len = events.length; i < len; i++){
5643 var ename = events[i];
5644 if(!this.events[ename]){ this.events[ename] = true; };
5645 o.on(ename, createHandler(ename), this);
5650 * Used to define events on this Observable
5651 * @param {Object} object The object with the events defined
5653 addEvents : function(o){
5657 Roo.applyIf(this.events, o);
5661 * Checks to see if this object has any listeners for a specified event
5662 * @param {String} eventName The name of the event to check for
5663 * @return {Boolean} True if the event is being listened for, else false
5665 hasListener : function(eventName){
5666 var e = this.events[eventName];
5667 return typeof e == "object" && e.listeners.length > 0;
5671 * Appends an event handler to this element (shorthand for addListener)
5672 * @param {String} eventName The type of event to listen for
5673 * @param {Function} handler The method the event invokes
5674 * @param {Object} scope (optional) The scope in which to execute the handler
5675 * function. The handler function's "this" context.
5676 * @param {Object} options (optional)
5679 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5681 * Removes a listener (shorthand for removeListener)
5682 * @param {String} eventName The type of event to listen for
5683 * @param {Function} handler The handler to remove
5684 * @param {Object} scope (optional) The scope (this object) for the handler
5687 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5690 * Starts capture on the specified Observable. All events will be passed
5691 * to the supplied function with the event name + standard signature of the event
5692 * <b>before</b> the event is fired. If the supplied function returns false,
5693 * the event will not fire.
5694 * @param {Observable} o The Observable to capture
5695 * @param {Function} fn The function to call
5696 * @param {Object} scope (optional) The scope (this object) for the fn
5699 Roo.util.Observable.capture = function(o, fn, scope){
5700 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5704 * Removes <b>all</b> added captures from the Observable.
5705 * @param {Observable} o The Observable to release
5708 Roo.util.Observable.releaseCapture = function(o){
5709 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5714 var createBuffered = function(h, o, scope){
5715 var task = new Roo.util.DelayedTask();
5717 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5721 var createSingle = function(h, e, fn, scope){
5723 e.removeListener(fn, scope);
5724 return h.apply(scope, arguments);
5728 var createDelayed = function(h, o, scope){
5730 var args = Array.prototype.slice.call(arguments, 0);
5731 setTimeout(function(){
5732 h.apply(scope, args);
5737 Roo.util.Event = function(obj, name){
5740 this.listeners = [];
5743 Roo.util.Event.prototype = {
5744 addListener : function(fn, scope, options){
5745 var o = options || {};
5746 scope = scope || this.obj;
5747 if(!this.isListening(fn, scope)){
5748 var l = {fn: fn, scope: scope, options: o};
5751 h = createDelayed(h, o, scope);
5754 h = createSingle(h, this, fn, scope);
5757 h = createBuffered(h, o, scope);
5760 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5761 this.listeners.push(l);
5763 this.listeners = this.listeners.slice(0);
5764 this.listeners.push(l);
5769 findListener : function(fn, scope){
5770 scope = scope || this.obj;
5771 var ls = this.listeners;
5772 for(var i = 0, len = ls.length; i < len; i++){
5774 if(l.fn == fn && l.scope == scope){
5781 isListening : function(fn, scope){
5782 return this.findListener(fn, scope) != -1;
5785 removeListener : function(fn, scope){
5787 if((index = this.findListener(fn, scope)) != -1){
5789 this.listeners.splice(index, 1);
5791 this.listeners = this.listeners.slice(0);
5792 this.listeners.splice(index, 1);
5799 clearListeners : function(){
5800 this.listeners = [];
5804 var ls = this.listeners, scope, len = ls.length;
5807 var args = Array.prototype.slice.call(arguments, 0);
5808 for(var i = 0; i < len; i++){
5810 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5811 this.firing = false;
5815 this.firing = false;
5822 * Ext JS Library 1.1.1
5823 * Copyright(c) 2006-2007, Ext JS, LLC.
5825 * Originally Released Under LGPL - original licence link has changed is not relivant.
5828 * <script type="text/javascript">
5832 * @class Roo.EventManager
5833 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5834 * several useful events directly.
5835 * See {@link Roo.EventObject} for more details on normalized event objects.
5838 Roo.EventManager = function(){
5839 var docReadyEvent, docReadyProcId, docReadyState = false;
5840 var resizeEvent, resizeTask, textEvent, textSize;
5841 var E = Roo.lib.Event;
5842 var D = Roo.lib.Dom;
5845 var fireDocReady = function(){
5847 docReadyState = true;
5850 clearInterval(docReadyProcId);
5852 if(Roo.isGecko || Roo.isOpera) {
5853 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5856 var defer = document.getElementById("ie-deferred-loader");
5858 defer.onreadystatechange = null;
5859 defer.parentNode.removeChild(defer);
5863 docReadyEvent.fire();
5864 docReadyEvent.clearListeners();
5869 var initDocReady = function(){
5870 docReadyEvent = new Roo.util.Event();
5871 if(Roo.isGecko || Roo.isOpera) {
5872 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5874 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5875 var defer = document.getElementById("ie-deferred-loader");
5876 defer.onreadystatechange = function(){
5877 if(this.readyState == "complete"){
5881 }else if(Roo.isSafari){
5882 docReadyProcId = setInterval(function(){
5883 var rs = document.readyState;
5884 if(rs == "complete") {
5889 // no matter what, make sure it fires on load
5890 E.on(window, "load", fireDocReady);
5893 var createBuffered = function(h, o){
5894 var task = new Roo.util.DelayedTask(h);
5896 // create new event object impl so new events don't wipe out properties
5897 e = new Roo.EventObjectImpl(e);
5898 task.delay(o.buffer, h, null, [e]);
5902 var createSingle = function(h, el, ename, fn){
5904 Roo.EventManager.removeListener(el, ename, fn);
5909 var createDelayed = function(h, o){
5911 // create new event object impl so new events don't wipe out properties
5912 e = new Roo.EventObjectImpl(e);
5913 setTimeout(function(){
5919 var listen = function(element, ename, opt, fn, scope){
5920 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5921 fn = fn || o.fn; scope = scope || o.scope;
5922 var el = Roo.getDom(element);
5924 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5926 var h = function(e){
5927 e = Roo.EventObject.setEvent(e);
5930 t = e.getTarget(o.delegate, el);
5937 if(o.stopEvent === true){
5940 if(o.preventDefault === true){
5943 if(o.stopPropagation === true){
5944 e.stopPropagation();
5947 if(o.normalized === false){
5951 fn.call(scope || el, e, t, o);
5954 h = createDelayed(h, o);
5957 h = createSingle(h, el, ename, fn);
5960 h = createBuffered(h, o);
5962 fn._handlers = fn._handlers || [];
5963 fn._handlers.push([Roo.id(el), ename, h]);
5966 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5967 el.addEventListener("DOMMouseScroll", h, false);
5968 E.on(window, 'unload', function(){
5969 el.removeEventListener("DOMMouseScroll", h, false);
5972 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5973 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5978 var stopListening = function(el, ename, fn){
5979 var id = Roo.id(el), hds = fn._handlers, hd = fn;
5981 for(var i = 0, len = hds.length; i < len; i++){
5983 if(h[0] == id && h[1] == ename){
5990 E.un(el, ename, hd);
5991 el = Roo.getDom(el);
5992 if(ename == "mousewheel" && el.addEventListener){
5993 el.removeEventListener("DOMMouseScroll", hd, false);
5995 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5996 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6000 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6007 * @scope Roo.EventManager
6012 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6013 * object with a Roo.EventObject
6014 * @param {Function} fn The method the event invokes
6015 * @param {Object} scope An object that becomes the scope of the handler
6016 * @param {boolean} override If true, the obj passed in becomes
6017 * the execution scope of the listener
6018 * @return {Function} The wrapped function
6021 wrap : function(fn, scope, override){
6023 Roo.EventObject.setEvent(e);
6024 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6029 * Appends an event handler to an element (shorthand for addListener)
6030 * @param {String/HTMLElement} element The html element or id to assign the
6031 * @param {String} eventName The type of event to listen for
6032 * @param {Function} handler The method the event invokes
6033 * @param {Object} scope (optional) The scope in which to execute the handler
6034 * function. The handler function's "this" context.
6035 * @param {Object} options (optional) An object containing handler configuration
6036 * properties. This may contain any of the following properties:<ul>
6037 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6038 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6039 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6040 * <li>preventDefault {Boolean} True to prevent the default action</li>
6041 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6042 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6043 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6044 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6045 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6046 * by the specified number of milliseconds. If the event fires again within that time, the original
6047 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6050 * <b>Combining Options</b><br>
6051 * Using the options argument, it is possible to combine different types of listeners:<br>
6053 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6055 el.on('click', this.onClick, this, {
6062 * <b>Attaching multiple handlers in 1 call</b><br>
6063 * The method also allows for a single argument to be passed which is a config object containing properties
6064 * which specify multiple handlers.
6074 fn: this.onMouseOver
6083 * Or a shorthand syntax:<br>
6086 'click' : this.onClick,
6087 'mouseover' : this.onMouseOver,
6088 'mouseout' : this.onMouseOut
6092 addListener : function(element, eventName, fn, scope, options){
6093 if(typeof eventName == "object"){
6099 if(typeof o[e] == "function"){
6101 listen(element, e, o, o[e], o.scope);
6103 // individual options
6104 listen(element, e, o[e]);
6109 return listen(element, eventName, options, fn, scope);
6113 * Removes an event handler
6115 * @param {String/HTMLElement} element The id or html element to remove the
6117 * @param {String} eventName The type of event
6118 * @param {Function} fn
6119 * @return {Boolean} True if a listener was actually removed
6121 removeListener : function(element, eventName, fn){
6122 return stopListening(element, eventName, fn);
6126 * Fires when the document is ready (before onload and before images are loaded). Can be
6127 * accessed shorthanded Roo.onReady().
6128 * @param {Function} fn The method the event invokes
6129 * @param {Object} scope An object that becomes the scope of the handler
6130 * @param {boolean} options
6132 onDocumentReady : function(fn, scope, options){
6133 if(docReadyState){ // if it already fired
6134 docReadyEvent.addListener(fn, scope, options);
6135 docReadyEvent.fire();
6136 docReadyEvent.clearListeners();
6142 docReadyEvent.addListener(fn, scope, options);
6146 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6147 * @param {Function} fn The method the event invokes
6148 * @param {Object} scope An object that becomes the scope of the handler
6149 * @param {boolean} options
6151 onWindowResize : function(fn, scope, options){
6153 resizeEvent = new Roo.util.Event();
6154 resizeTask = new Roo.util.DelayedTask(function(){
6155 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6157 E.on(window, "resize", function(){
6159 resizeTask.delay(50);
6161 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6165 resizeEvent.addListener(fn, scope, options);
6169 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6170 * @param {Function} fn The method the event invokes
6171 * @param {Object} scope An object that becomes the scope of the handler
6172 * @param {boolean} options
6174 onTextResize : function(fn, scope, options){
6176 textEvent = new Roo.util.Event();
6177 var textEl = new Roo.Element(document.createElement('div'));
6178 textEl.dom.className = 'x-text-resize';
6179 textEl.dom.innerHTML = 'X';
6180 textEl.appendTo(document.body);
6181 textSize = textEl.dom.offsetHeight;
6182 setInterval(function(){
6183 if(textEl.dom.offsetHeight != textSize){
6184 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6186 }, this.textResizeInterval);
6188 textEvent.addListener(fn, scope, options);
6192 * Removes the passed window resize listener.
6193 * @param {Function} fn The method the event invokes
6194 * @param {Object} scope The scope of handler
6196 removeResizeListener : function(fn, scope){
6198 resizeEvent.removeListener(fn, scope);
6203 fireResize : function(){
6205 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6209 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6213 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6215 textResizeInterval : 50
6220 * @scopeAlias pub=Roo.EventManager
6224 * Appends an event handler to an element (shorthand for addListener)
6225 * @param {String/HTMLElement} element The html element or id to assign the
6226 * @param {String} eventName The type of event to listen for
6227 * @param {Function} handler The method the event invokes
6228 * @param {Object} scope (optional) The scope in which to execute the handler
6229 * function. The handler function's "this" context.
6230 * @param {Object} options (optional) An object containing handler configuration
6231 * properties. This may contain any of the following properties:<ul>
6232 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6233 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6234 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6235 * <li>preventDefault {Boolean} True to prevent the default action</li>
6236 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6237 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6238 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6239 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6240 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6241 * by the specified number of milliseconds. If the event fires again within that time, the original
6242 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6245 * <b>Combining Options</b><br>
6246 * Using the options argument, it is possible to combine different types of listeners:<br>
6248 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6250 el.on('click', this.onClick, this, {
6257 * <b>Attaching multiple handlers in 1 call</b><br>
6258 * The method also allows for a single argument to be passed which is a config object containing properties
6259 * which specify multiple handlers.
6269 fn: this.onMouseOver
6278 * Or a shorthand syntax:<br>
6281 'click' : this.onClick,
6282 'mouseover' : this.onMouseOver,
6283 'mouseout' : this.onMouseOut
6287 pub.on = pub.addListener;
6288 pub.un = pub.removeListener;
6290 pub.stoppedMouseDownEvent = new Roo.util.Event();
6294 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6295 * @param {Function} fn The method the event invokes
6296 * @param {Object} scope An object that becomes the scope of the handler
6297 * @param {boolean} override If true, the obj passed in becomes
6298 * the execution scope of the listener
6302 Roo.onReady = Roo.EventManager.onDocumentReady;
6304 Roo.onReady(function(){
6305 var bd = Roo.get(document.body);
6310 : Roo.isGecko ? "roo-gecko"
6311 : Roo.isOpera ? "roo-opera"
6312 : Roo.isSafari ? "roo-safari" : ""];
6315 cls.push("roo-mac");
6318 cls.push("roo-linux");
6320 if(Roo.isBorderBox){
6321 cls.push('roo-border-box');
6323 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6324 var p = bd.dom.parentNode;
6326 p.className += ' roo-strict';
6329 bd.addClass(cls.join(' '));
6333 * @class Roo.EventObject
6334 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6335 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6338 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6340 var target = e.getTarget();
6343 var myDiv = Roo.get("myDiv");
6344 myDiv.on("click", handleClick);
6346 Roo.EventManager.on("myDiv", 'click', handleClick);
6347 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6351 Roo.EventObject = function(){
6353 var E = Roo.lib.Event;
6355 // safari keypress events for special keys return bad keycodes
6358 63235 : 39, // right
6361 63276 : 33, // page up
6362 63277 : 34, // page down
6363 63272 : 46, // delete
6368 // normalize button clicks
6369 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6370 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6372 Roo.EventObjectImpl = function(e){
6374 this.setEvent(e.browserEvent || e);
6377 Roo.EventObjectImpl.prototype = {
6379 * Used to fix doc tools.
6380 * @scope Roo.EventObject.prototype
6386 /** The normal browser event */
6387 browserEvent : null,
6388 /** The button pressed in a mouse event */
6390 /** True if the shift key was down during the event */
6392 /** True if the control key was down during the event */
6394 /** True if the alt key was down during the event */
6453 setEvent : function(e){
6454 if(e == this || (e && e.browserEvent)){ // already wrapped
6457 this.browserEvent = e;
6459 // normalize buttons
6460 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6461 if(e.type == 'click' && this.button == -1){
6465 this.shiftKey = e.shiftKey;
6466 // mac metaKey behaves like ctrlKey
6467 this.ctrlKey = e.ctrlKey || e.metaKey;
6468 this.altKey = e.altKey;
6469 // in getKey these will be normalized for the mac
6470 this.keyCode = e.keyCode;
6471 // keyup warnings on firefox.
6472 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6473 // cache the target for the delayed and or buffered events
6474 this.target = E.getTarget(e);
6476 this.xy = E.getXY(e);
6479 this.shiftKey = false;
6480 this.ctrlKey = false;
6481 this.altKey = false;
6491 * Stop the event (preventDefault and stopPropagation)
6493 stopEvent : function(){
6494 if(this.browserEvent){
6495 if(this.browserEvent.type == 'mousedown'){
6496 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6498 E.stopEvent(this.browserEvent);
6503 * Prevents the browsers default handling of the event.
6505 preventDefault : function(){
6506 if(this.browserEvent){
6507 E.preventDefault(this.browserEvent);
6512 isNavKeyPress : function(){
6513 var k = this.keyCode;
6514 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6515 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6518 isSpecialKey : function(){
6519 var k = this.keyCode;
6520 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6521 (k == 16) || (k == 17) ||
6522 (k >= 18 && k <= 20) ||
6523 (k >= 33 && k <= 35) ||
6524 (k >= 36 && k <= 39) ||
6525 (k >= 44 && k <= 45);
6528 * Cancels bubbling of the event.
6530 stopPropagation : function(){
6531 if(this.browserEvent){
6532 if(this.type == 'mousedown'){
6533 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6535 E.stopPropagation(this.browserEvent);
6540 * Gets the key code for the event.
6543 getCharCode : function(){
6544 return this.charCode || this.keyCode;
6548 * Returns a normalized keyCode for the event.
6549 * @return {Number} The key code
6551 getKey : function(){
6552 var k = this.keyCode || this.charCode;
6553 return Roo.isSafari ? (safariKeys[k] || k) : k;
6557 * Gets the x coordinate of the event.
6560 getPageX : function(){
6565 * Gets the y coordinate of the event.
6568 getPageY : function(){
6573 * Gets the time of the event.
6576 getTime : function(){
6577 if(this.browserEvent){
6578 return E.getTime(this.browserEvent);
6584 * Gets the page coordinates of the event.
6585 * @return {Array} The xy values like [x, y]
6592 * Gets the target for the event.
6593 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6594 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6595 search as a number or element (defaults to 10 || document.body)
6596 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6597 * @return {HTMLelement}
6599 getTarget : function(selector, maxDepth, returnEl){
6600 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6603 * Gets the related target.
6604 * @return {HTMLElement}
6606 getRelatedTarget : function(){
6607 if(this.browserEvent){
6608 return E.getRelatedTarget(this.browserEvent);
6614 * Normalizes mouse wheel delta across browsers
6615 * @return {Number} The delta
6617 getWheelDelta : function(){
6618 var e = this.browserEvent;
6620 if(e.wheelDelta){ /* IE/Opera. */
6621 delta = e.wheelDelta/120;
6622 }else if(e.detail){ /* Mozilla case. */
6623 delta = -e.detail/3;
6629 * Returns true if the control, meta, shift or alt key was pressed during this event.
6632 hasModifier : function(){
6633 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6637 * Returns true if the target of this event equals el or is a child of el
6638 * @param {String/HTMLElement/Element} el
6639 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6642 within : function(el, related){
6643 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6644 return t && Roo.fly(el).contains(t);
6647 getPoint : function(){
6648 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6652 return new Roo.EventObjectImpl();
6657 * Ext JS Library 1.1.1
6658 * Copyright(c) 2006-2007, Ext JS, LLC.
6660 * Originally Released Under LGPL - original licence link has changed is not relivant.
6663 * <script type="text/javascript">
6667 // was in Composite Element!??!?!
6670 var D = Roo.lib.Dom;
6671 var E = Roo.lib.Event;
6672 var A = Roo.lib.Anim;
6674 // local style camelizing for speed
6676 var camelRe = /(-[a-z])/gi;
6677 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6678 var view = document.defaultView;
6681 * @class Roo.Element
6682 * Represents an Element in the DOM.<br><br>
6685 var el = Roo.get("my-div");
6688 var el = getEl("my-div");
6690 // or with a DOM element
6691 var el = Roo.get(myDivElement);
6693 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6694 * each call instead of constructing a new one.<br><br>
6695 * <b>Animations</b><br />
6696 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6697 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6699 Option Default Description
6700 --------- -------- ---------------------------------------------
6701 duration .35 The duration of the animation in seconds
6702 easing easeOut The YUI easing method
6703 callback none A function to execute when the anim completes
6704 scope this The scope (this) of the callback function
6706 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6707 * manipulate the animation. Here's an example:
6709 var el = Roo.get("my-div");
6714 // default animation
6715 el.setWidth(100, true);
6717 // animation with some options set
6724 // using the "anim" property to get the Anim object
6730 el.setWidth(100, opt);
6732 if(opt.anim.isAnimated()){
6736 * <b> Composite (Collections of) Elements</b><br />
6737 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6738 * @constructor Create a new Element directly.
6739 * @param {String/HTMLElement} element
6740 * @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).
6742 Roo.Element = function(element, forceNew){
6743 var dom = typeof element == "string" ?
6744 document.getElementById(element) : element;
6745 if(!dom){ // invalid id/element
6749 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6750 return Roo.Element.cache[id];
6760 * The DOM element ID
6763 this.id = id || Roo.id(dom);
6766 var El = Roo.Element;
6770 * The element's default display mode (defaults to "")
6773 originalDisplay : "",
6777 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6782 * Sets the element's visibility mode. When setVisible() is called it
6783 * will use this to determine whether to set the visibility or the display property.
6784 * @param visMode Element.VISIBILITY or Element.DISPLAY
6785 * @return {Roo.Element} this
6787 setVisibilityMode : function(visMode){
6788 this.visibilityMode = visMode;
6792 * Convenience method for setVisibilityMode(Element.DISPLAY)
6793 * @param {String} display (optional) What to set display to when visible
6794 * @return {Roo.Element} this
6796 enableDisplayMode : function(display){
6797 this.setVisibilityMode(El.DISPLAY);
6798 if(typeof display != "undefined") this.originalDisplay = display;
6803 * 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)
6804 * @param {String} selector The simple selector to test
6805 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6806 search as a number or element (defaults to 10 || document.body)
6807 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6808 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6810 findParent : function(simpleSelector, maxDepth, returnEl){
6811 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6812 maxDepth = maxDepth || 50;
6813 if(typeof maxDepth != "number"){
6814 stopEl = Roo.getDom(maxDepth);
6817 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6818 if(dq.is(p, simpleSelector)){
6819 return returnEl ? Roo.get(p) : p;
6829 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6830 * @param {String} selector The simple selector to test
6831 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6832 search as a number or element (defaults to 10 || document.body)
6833 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6834 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6836 findParentNode : function(simpleSelector, maxDepth, returnEl){
6837 var p = Roo.fly(this.dom.parentNode, '_internal');
6838 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6842 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6843 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6844 * @param {String} selector The simple selector to test
6845 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6846 search as a number or element (defaults to 10 || document.body)
6847 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6849 up : function(simpleSelector, maxDepth){
6850 return this.findParentNode(simpleSelector, maxDepth, true);
6856 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6857 * @param {String} selector The simple selector to test
6858 * @return {Boolean} True if this element matches the selector, else false
6860 is : function(simpleSelector){
6861 return Roo.DomQuery.is(this.dom, simpleSelector);
6865 * Perform animation on this element.
6866 * @param {Object} args The YUI animation control args
6867 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6868 * @param {Function} onComplete (optional) Function to call when animation completes
6869 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6870 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6871 * @return {Roo.Element} this
6873 animate : function(args, duration, onComplete, easing, animType){
6874 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6879 * @private Internal animation call
6881 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6882 animType = animType || 'run';
6884 var anim = Roo.lib.Anim[animType](
6886 (opt.duration || defaultDur) || .35,
6887 (opt.easing || defaultEase) || 'easeOut',
6889 Roo.callback(cb, this);
6890 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6898 // private legacy anim prep
6899 preanim : function(a, i){
6900 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6904 * Removes worthless text nodes
6905 * @param {Boolean} forceReclean (optional) By default the element
6906 * keeps track if it has been cleaned already so
6907 * you can call this over and over. However, if you update the element and
6908 * need to force a reclean, you can pass true.
6910 clean : function(forceReclean){
6911 if(this.isCleaned && forceReclean !== true){
6915 var d = this.dom, n = d.firstChild, ni = -1;
6917 var nx = n.nextSibling;
6918 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6925 this.isCleaned = true;
6930 calcOffsetsTo : function(el){
6933 var restorePos = false;
6934 if(el.getStyle('position') == 'static'){
6935 el.position('relative');
6940 while(op && op != d && op.tagName != 'HTML'){
6943 op = op.offsetParent;
6946 el.position('static');
6952 * Scrolls this element into view within the passed container.
6953 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6954 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6955 * @return {Roo.Element} this
6957 scrollIntoView : function(container, hscroll){
6958 var c = Roo.getDom(container) || document.body;
6961 var o = this.calcOffsetsTo(c),
6964 b = t+el.offsetHeight,
6965 r = l+el.offsetWidth;
6967 var ch = c.clientHeight;
6968 var ct = parseInt(c.scrollTop, 10);
6969 var cl = parseInt(c.scrollLeft, 10);
6971 var cr = cl + c.clientWidth;
6979 if(hscroll !== false){
6983 c.scrollLeft = r-c.clientWidth;
6990 scrollChildIntoView : function(child, hscroll){
6991 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6995 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6996 * the new height may not be available immediately.
6997 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6998 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6999 * @param {Function} onComplete (optional) Function to call when animation completes
7000 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7001 * @return {Roo.Element} this
7003 autoHeight : function(animate, duration, onComplete, easing){
7004 var oldHeight = this.getHeight();
7006 this.setHeight(1); // force clipping
7007 setTimeout(function(){
7008 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7010 this.setHeight(height);
7012 if(typeof onComplete == "function"){
7016 this.setHeight(oldHeight); // restore original height
7017 this.setHeight(height, animate, duration, function(){
7019 if(typeof onComplete == "function") onComplete();
7020 }.createDelegate(this), easing);
7022 }.createDelegate(this), 0);
7027 * Returns true if this element is an ancestor of the passed element
7028 * @param {HTMLElement/String} el The element to check
7029 * @return {Boolean} True if this element is an ancestor of el, else false
7031 contains : function(el){
7032 if(!el){return false;}
7033 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7037 * Checks whether the element is currently visible using both visibility and display properties.
7038 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7039 * @return {Boolean} True if the element is currently visible, else false
7041 isVisible : function(deep) {
7042 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7043 if(deep !== true || !vis){
7046 var p = this.dom.parentNode;
7047 while(p && p.tagName.toLowerCase() != "body"){
7048 if(!Roo.fly(p, '_isVisible').isVisible()){
7057 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7058 * @param {String} selector The CSS selector
7059 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7060 * @return {CompositeElement/CompositeElementLite} The composite element
7062 select : function(selector, unique){
7063 return El.select(selector, unique, this.dom);
7067 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7068 * @param {String} selector The CSS selector
7069 * @return {Array} An array of the matched nodes
7071 query : function(selector, unique){
7072 return Roo.DomQuery.select(selector, this.dom);
7076 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7077 * @param {String} selector The CSS selector
7078 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7079 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7081 child : function(selector, returnDom){
7082 var n = Roo.DomQuery.selectNode(selector, this.dom);
7083 return returnDom ? n : Roo.get(n);
7087 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7088 * @param {String} selector The CSS selector
7089 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7090 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7092 down : function(selector, returnDom){
7093 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7094 return returnDom ? n : Roo.get(n);
7098 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7099 * @param {String} group The group the DD object is member of
7100 * @param {Object} config The DD config object
7101 * @param {Object} overrides An object containing methods to override/implement on the DD object
7102 * @return {Roo.dd.DD} The DD object
7104 initDD : function(group, config, overrides){
7105 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7106 return Roo.apply(dd, overrides);
7110 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7111 * @param {String} group The group the DDProxy object is member of
7112 * @param {Object} config The DDProxy config object
7113 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7114 * @return {Roo.dd.DDProxy} The DDProxy object
7116 initDDProxy : function(group, config, overrides){
7117 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7118 return Roo.apply(dd, overrides);
7122 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7123 * @param {String} group The group the DDTarget object is member of
7124 * @param {Object} config The DDTarget config object
7125 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7126 * @return {Roo.dd.DDTarget} The DDTarget object
7128 initDDTarget : function(group, config, overrides){
7129 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7130 return Roo.apply(dd, overrides);
7134 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7135 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7136 * @param {Boolean} visible Whether the element is visible
7137 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7138 * @return {Roo.Element} this
7140 setVisible : function(visible, animate){
7142 if(this.visibilityMode == El.DISPLAY){
7143 this.setDisplayed(visible);
7146 this.dom.style.visibility = visible ? "visible" : "hidden";
7149 // closure for composites
7151 var visMode = this.visibilityMode;
7153 this.setOpacity(.01);
7154 this.setVisible(true);
7156 this.anim({opacity: { to: (visible?1:0) }},
7157 this.preanim(arguments, 1),
7158 null, .35, 'easeIn', function(){
7160 if(visMode == El.DISPLAY){
7161 dom.style.display = "none";
7163 dom.style.visibility = "hidden";
7165 Roo.get(dom).setOpacity(1);
7173 * Returns true if display is not "none"
7176 isDisplayed : function() {
7177 return this.getStyle("display") != "none";
7181 * Toggles the element's visibility or display, depending on visibility mode.
7182 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7183 * @return {Roo.Element} this
7185 toggle : function(animate){
7186 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7191 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7192 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7193 * @return {Roo.Element} this
7195 setDisplayed : function(value) {
7196 if(typeof value == "boolean"){
7197 value = value ? this.originalDisplay : "none";
7199 this.setStyle("display", value);
7204 * Tries to focus the element. Any exceptions are caught and ignored.
7205 * @return {Roo.Element} this
7207 focus : function() {
7215 * Tries to blur the element. Any exceptions are caught and ignored.
7216 * @return {Roo.Element} this
7226 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7227 * @param {String/Array} className The CSS class to add, or an array of classes
7228 * @return {Roo.Element} this
7230 addClass : function(className){
7231 if(className instanceof Array){
7232 for(var i = 0, len = className.length; i < len; i++) {
7233 this.addClass(className[i]);
7236 if(className && !this.hasClass(className)){
7237 this.dom.className = this.dom.className + " " + className;
7244 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7245 * @param {String/Array} className The CSS class to add, or an array of classes
7246 * @return {Roo.Element} this
7248 radioClass : function(className){
7249 var siblings = this.dom.parentNode.childNodes;
7250 for(var i = 0; i < siblings.length; i++) {
7251 var s = siblings[i];
7252 if(s.nodeType == 1){
7253 Roo.get(s).removeClass(className);
7256 this.addClass(className);
7261 * Removes one or more CSS classes from the element.
7262 * @param {String/Array} className The CSS class to remove, or an array of classes
7263 * @return {Roo.Element} this
7265 removeClass : function(className){
7266 if(!className || !this.dom.className){
7269 if(className instanceof Array){
7270 for(var i = 0, len = className.length; i < len; i++) {
7271 this.removeClass(className[i]);
7274 if(this.hasClass(className)){
7275 var re = this.classReCache[className];
7277 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7278 this.classReCache[className] = re;
7280 this.dom.className =
7281 this.dom.className.replace(re, " ");
7291 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7292 * @param {String} className The CSS class to toggle
7293 * @return {Roo.Element} this
7295 toggleClass : function(className){
7296 if(this.hasClass(className)){
7297 this.removeClass(className);
7299 this.addClass(className);
7305 * Checks if the specified CSS class exists on this element's DOM node.
7306 * @param {String} className The CSS class to check for
7307 * @return {Boolean} True if the class exists, else false
7309 hasClass : function(className){
7310 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7314 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7315 * @param {String} oldClassName The CSS class to replace
7316 * @param {String} newClassName The replacement CSS class
7317 * @return {Roo.Element} this
7319 replaceClass : function(oldClassName, newClassName){
7320 this.removeClass(oldClassName);
7321 this.addClass(newClassName);
7326 * Returns an object with properties matching the styles requested.
7327 * For example, el.getStyles('color', 'font-size', 'width') might return
7328 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7329 * @param {String} style1 A style name
7330 * @param {String} style2 A style name
7331 * @param {String} etc.
7332 * @return {Object} The style object
7334 getStyles : function(){
7335 var a = arguments, len = a.length, r = {};
7336 for(var i = 0; i < len; i++){
7337 r[a[i]] = this.getStyle(a[i]);
7343 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7344 * @param {String} property The style property whose value is returned.
7345 * @return {String} The current value of the style property for this element.
7347 getStyle : function(){
7348 return view && view.getComputedStyle ?
7350 var el = this.dom, v, cs, camel;
7351 if(prop == 'float'){
7354 if(el.style && (v = el.style[prop])){
7357 if(cs = view.getComputedStyle(el, "")){
7358 if(!(camel = propCache[prop])){
7359 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7366 var el = this.dom, v, cs, camel;
7367 if(prop == 'opacity'){
7368 if(typeof el.style.filter == 'string'){
7369 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7371 var fv = parseFloat(m[1]);
7373 return fv ? fv / 100 : 0;
7378 }else if(prop == 'float'){
7379 prop = "styleFloat";
7381 if(!(camel = propCache[prop])){
7382 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7384 if(v = el.style[camel]){
7387 if(cs = el.currentStyle){
7395 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7396 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7397 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7398 * @return {Roo.Element} this
7400 setStyle : function(prop, value){
7401 if(typeof prop == "string"){
7403 if (prop == 'float') {
7404 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7409 if(!(camel = propCache[prop])){
7410 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7413 if(camel == 'opacity') {
7414 this.setOpacity(value);
7416 this.dom.style[camel] = value;
7419 for(var style in prop){
7420 if(typeof prop[style] != "function"){
7421 this.setStyle(style, prop[style]);
7429 * More flexible version of {@link #setStyle} for setting style properties.
7430 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7431 * a function which returns such a specification.
7432 * @return {Roo.Element} this
7434 applyStyles : function(style){
7435 Roo.DomHelper.applyStyles(this.dom, style);
7440 * 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).
7441 * @return {Number} The X position of the element
7444 return D.getX(this.dom);
7448 * 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).
7449 * @return {Number} The Y position of the element
7452 return D.getY(this.dom);
7456 * 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).
7457 * @return {Array} The XY position of the element
7460 return D.getXY(this.dom);
7464 * 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).
7465 * @param {Number} The X position of the element
7466 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7467 * @return {Roo.Element} this
7469 setX : function(x, animate){
7471 D.setX(this.dom, x);
7473 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7479 * 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).
7480 * @param {Number} The Y position of the element
7481 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7482 * @return {Roo.Element} this
7484 setY : function(y, animate){
7486 D.setY(this.dom, y);
7488 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7494 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7495 * @param {String} left The left CSS property value
7496 * @return {Roo.Element} this
7498 setLeft : function(left){
7499 this.setStyle("left", this.addUnits(left));
7504 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7505 * @param {String} top The top CSS property value
7506 * @return {Roo.Element} this
7508 setTop : function(top){
7509 this.setStyle("top", this.addUnits(top));
7514 * Sets the element's CSS right style.
7515 * @param {String} right The right CSS property value
7516 * @return {Roo.Element} this
7518 setRight : function(right){
7519 this.setStyle("right", this.addUnits(right));
7524 * Sets the element's CSS bottom style.
7525 * @param {String} bottom The bottom CSS property value
7526 * @return {Roo.Element} this
7528 setBottom : function(bottom){
7529 this.setStyle("bottom", this.addUnits(bottom));
7534 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7535 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7536 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7537 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7538 * @return {Roo.Element} this
7540 setXY : function(pos, animate){
7542 D.setXY(this.dom, pos);
7544 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
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 {Number} x X value for new position (coordinates are page-based)
7553 * @param {Number} y Y value for new position (coordinates are page-based)
7554 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7555 * @return {Roo.Element} this
7557 setLocation : function(x, y, animate){
7558 this.setXY([x, y], this.preanim(arguments, 2));
7563 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7564 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7565 * @param {Number} x X value for new position (coordinates are page-based)
7566 * @param {Number} y Y value for new position (coordinates are page-based)
7567 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7568 * @return {Roo.Element} this
7570 moveTo : function(x, y, animate){
7571 this.setXY([x, y], this.preanim(arguments, 2));
7576 * Returns the region of the given element.
7577 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7578 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7580 getRegion : function(){
7581 return D.getRegion(this.dom);
7585 * Returns the offset height of the element
7586 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7587 * @return {Number} The element's height
7589 getHeight : function(contentHeight){
7590 var h = this.dom.offsetHeight || 0;
7591 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7595 * Returns the offset width of the element
7596 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7597 * @return {Number} The element's width
7599 getWidth : function(contentWidth){
7600 var w = this.dom.offsetWidth || 0;
7601 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7605 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7606 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7607 * if a height has not been set using CSS.
7610 getComputedHeight : function(){
7611 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7613 h = parseInt(this.getStyle('height'), 10) || 0;
7614 if(!this.isBorderBox()){
7615 h += this.getFrameWidth('tb');
7622 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7623 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7624 * if a width has not been set using CSS.
7627 getComputedWidth : function(){
7628 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7630 w = parseInt(this.getStyle('width'), 10) || 0;
7631 if(!this.isBorderBox()){
7632 w += this.getFrameWidth('lr');
7639 * Returns the size of the element.
7640 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7641 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7643 getSize : function(contentSize){
7644 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7648 * Returns the width and height of the viewport.
7649 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7651 getViewSize : function(){
7652 var d = this.dom, doc = document, aw = 0, ah = 0;
7653 if(d == doc || d == doc.body){
7654 return {width : D.getViewWidth(), height: D.getViewHeight()};
7657 width : d.clientWidth,
7658 height: d.clientHeight
7664 * Returns the value of the "value" attribute
7665 * @param {Boolean} asNumber true to parse the value as a number
7666 * @return {String/Number}
7668 getValue : function(asNumber){
7669 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7673 adjustWidth : function(width){
7674 if(typeof width == "number"){
7675 if(this.autoBoxAdjust && !this.isBorderBox()){
7676 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7686 adjustHeight : function(height){
7687 if(typeof height == "number"){
7688 if(this.autoBoxAdjust && !this.isBorderBox()){
7689 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7699 * Set the width of the element
7700 * @param {Number} width The new width
7701 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7702 * @return {Roo.Element} this
7704 setWidth : function(width, animate){
7705 width = this.adjustWidth(width);
7707 this.dom.style.width = this.addUnits(width);
7709 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7715 * Set the height of the element
7716 * @param {Number} height The new height
7717 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7718 * @return {Roo.Element} this
7720 setHeight : function(height, animate){
7721 height = this.adjustHeight(height);
7723 this.dom.style.height = this.addUnits(height);
7725 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7731 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7732 * @param {Number} width The new width
7733 * @param {Number} height The new height
7734 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7735 * @return {Roo.Element} this
7737 setSize : function(width, height, animate){
7738 if(typeof width == "object"){ // in case of object from getSize()
7739 height = width.height; width = width.width;
7741 width = this.adjustWidth(width); height = this.adjustHeight(height);
7743 this.dom.style.width = this.addUnits(width);
7744 this.dom.style.height = this.addUnits(height);
7746 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7752 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7753 * @param {Number} x X value for new position (coordinates are page-based)
7754 * @param {Number} y Y value for new position (coordinates are page-based)
7755 * @param {Number} width The new width
7756 * @param {Number} height The new height
7757 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7758 * @return {Roo.Element} this
7760 setBounds : function(x, y, width, height, animate){
7762 this.setSize(width, height);
7763 this.setLocation(x, y);
7765 width = this.adjustWidth(width); height = this.adjustHeight(height);
7766 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7767 this.preanim(arguments, 4), 'motion');
7773 * 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.
7774 * @param {Roo.lib.Region} region The region to fill
7775 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7776 * @return {Roo.Element} this
7778 setRegion : function(region, animate){
7779 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7784 * Appends an event handler
7786 * @param {String} eventName The type of event to append
7787 * @param {Function} fn The method the event invokes
7788 * @param {Object} scope (optional) The scope (this object) of the fn
7789 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7791 addListener : function(eventName, fn, scope, options){
7792 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7796 * Removes an event handler from this element
7797 * @param {String} eventName the type of event to remove
7798 * @param {Function} fn the method the event invokes
7799 * @return {Roo.Element} this
7801 removeListener : function(eventName, fn){
7802 Roo.EventManager.removeListener(this.dom, eventName, fn);
7807 * Removes all previous added listeners from this element
7808 * @return {Roo.Element} this
7810 removeAllListeners : function(){
7811 E.purgeElement(this.dom);
7815 relayEvent : function(eventName, observable){
7816 this.on(eventName, function(e){
7817 observable.fireEvent(eventName, e);
7822 * Set the opacity of the element
7823 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7824 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7825 * @return {Roo.Element} this
7827 setOpacity : function(opacity, animate){
7829 var s = this.dom.style;
7832 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7833 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7835 s.opacity = opacity;
7838 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7844 * Gets the left X coordinate
7845 * @param {Boolean} local True to get the local css position instead of page coordinate
7848 getLeft : function(local){
7852 return parseInt(this.getStyle("left"), 10) || 0;
7857 * Gets the right X coordinate of the element (element X position + element width)
7858 * @param {Boolean} local True to get the local css position instead of page coordinate
7861 getRight : function(local){
7863 return this.getX() + this.getWidth();
7865 return (this.getLeft(true) + this.getWidth()) || 0;
7870 * Gets the top Y coordinate
7871 * @param {Boolean} local True to get the local css position instead of page coordinate
7874 getTop : function(local) {
7878 return parseInt(this.getStyle("top"), 10) || 0;
7883 * Gets the bottom Y coordinate of the element (element Y position + element height)
7884 * @param {Boolean} local True to get the local css position instead of page coordinate
7887 getBottom : function(local){
7889 return this.getY() + this.getHeight();
7891 return (this.getTop(true) + this.getHeight()) || 0;
7896 * Initializes positioning on this element. If a desired position is not passed, it will make the
7897 * the element positioned relative IF it is not already positioned.
7898 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7899 * @param {Number} zIndex (optional) The zIndex to apply
7900 * @param {Number} x (optional) Set the page X position
7901 * @param {Number} y (optional) Set the page Y position
7903 position : function(pos, zIndex, x, y){
7905 if(this.getStyle('position') == 'static'){
7906 this.setStyle('position', 'relative');
7909 this.setStyle("position", pos);
7912 this.setStyle("z-index", zIndex);
7914 if(x !== undefined && y !== undefined){
7916 }else if(x !== undefined){
7918 }else if(y !== undefined){
7924 * Clear positioning back to the default when the document was loaded
7925 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7926 * @return {Roo.Element} this
7928 clearPositioning : function(value){
7936 "position" : "static"
7942 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7943 * snapshot before performing an update and then restoring the element.
7946 getPositioning : function(){
7947 var l = this.getStyle("left");
7948 var t = this.getStyle("top");
7950 "position" : this.getStyle("position"),
7952 "right" : l ? "" : this.getStyle("right"),
7954 "bottom" : t ? "" : this.getStyle("bottom"),
7955 "z-index" : this.getStyle("z-index")
7960 * Gets the width of the border(s) for the specified side(s)
7961 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7962 * passing lr would get the border (l)eft width + the border (r)ight width.
7963 * @return {Number} The width of the sides passed added together
7965 getBorderWidth : function(side){
7966 return this.addStyles(side, El.borders);
7970 * Gets the width of the padding(s) for the specified side(s)
7971 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7972 * passing lr would get the padding (l)eft + the padding (r)ight.
7973 * @return {Number} The padding of the sides passed added together
7975 getPadding : function(side){
7976 return this.addStyles(side, El.paddings);
7980 * Set positioning with an object returned by getPositioning().
7981 * @param {Object} posCfg
7982 * @return {Roo.Element} this
7984 setPositioning : function(pc){
7985 this.applyStyles(pc);
7986 if(pc.right == "auto"){
7987 this.dom.style.right = "";
7989 if(pc.bottom == "auto"){
7990 this.dom.style.bottom = "";
7996 fixDisplay : function(){
7997 if(this.getStyle("display") == "none"){
7998 this.setStyle("visibility", "hidden");
7999 this.setStyle("display", this.originalDisplay); // first try reverting to default
8000 if(this.getStyle("display") == "none"){ // if that fails, default to block
8001 this.setStyle("display", "block");
8007 * Quick set left and top adding default units
8008 * @param {String} left The left CSS property value
8009 * @param {String} top The top CSS property value
8010 * @return {Roo.Element} this
8012 setLeftTop : function(left, top){
8013 this.dom.style.left = this.addUnits(left);
8014 this.dom.style.top = this.addUnits(top);
8019 * Move this element relative to its current position.
8020 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8021 * @param {Number} distance How far to move the element in pixels
8022 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8023 * @return {Roo.Element} this
8025 move : function(direction, distance, animate){
8026 var xy = this.getXY();
8027 direction = direction.toLowerCase();
8031 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8035 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8040 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8045 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8052 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8053 * @return {Roo.Element} this
8056 if(!this.isClipped){
8057 this.isClipped = true;
8058 this.originalClip = {
8059 "o": this.getStyle("overflow"),
8060 "x": this.getStyle("overflow-x"),
8061 "y": this.getStyle("overflow-y")
8063 this.setStyle("overflow", "hidden");
8064 this.setStyle("overflow-x", "hidden");
8065 this.setStyle("overflow-y", "hidden");
8071 * Return clipping (overflow) to original clipping before clip() was called
8072 * @return {Roo.Element} this
8074 unclip : function(){
8076 this.isClipped = false;
8077 var o = this.originalClip;
8078 if(o.o){this.setStyle("overflow", o.o);}
8079 if(o.x){this.setStyle("overflow-x", o.x);}
8080 if(o.y){this.setStyle("overflow-y", o.y);}
8087 * Gets the x,y coordinates specified by the anchor position on the element.
8088 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8089 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8090 * {width: (target width), height: (target height)} (defaults to the element's current size)
8091 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8092 * @return {Array} [x, y] An array containing the element's x and y coordinates
8094 getAnchorXY : function(anchor, local, s){
8095 //Passing a different size is useful for pre-calculating anchors,
8096 //especially for anchored animations that change the el size.
8098 var w, h, vp = false;
8101 if(d == document.body || d == document){
8103 w = D.getViewWidth(); h = D.getViewHeight();
8105 w = this.getWidth(); h = this.getHeight();
8108 w = s.width; h = s.height;
8110 var x = 0, y = 0, r = Math.round;
8111 switch((anchor || "tl").toLowerCase()){
8153 var sc = this.getScroll();
8154 return [x + sc.left, y + sc.top];
8156 //Add the element's offset xy
8157 var o = this.getXY();
8158 return [x+o[0], y+o[1]];
8162 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8163 * supported position values.
8164 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8165 * @param {String} position The position to align to.
8166 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8167 * @return {Array} [x, y]
8169 getAlignToXY : function(el, p, o){
8173 throw "Element.alignTo with an element that doesn't exist";
8175 var c = false; //constrain to viewport
8176 var p1 = "", p2 = "";
8183 }else if(p.indexOf("-") == -1){
8186 p = p.toLowerCase();
8187 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8189 throw "Element.alignTo with an invalid alignment " + p;
8191 p1 = m[1]; p2 = m[2]; c = !!m[3];
8193 //Subtract the aligned el's internal xy from the target's offset xy
8194 //plus custom offset to get the aligned el's new offset xy
8195 var a1 = this.getAnchorXY(p1, true);
8196 var a2 = el.getAnchorXY(p2, false);
8197 var x = a2[0] - a1[0] + o[0];
8198 var y = a2[1] - a1[1] + o[1];
8200 //constrain the aligned el to viewport if necessary
8201 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8202 // 5px of margin for ie
8203 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8205 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8206 //perpendicular to the vp border, allow the aligned el to slide on that border,
8207 //otherwise swap the aligned el to the opposite border of the target.
8208 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8209 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8210 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8211 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8214 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8215 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8217 if((x+w) > dw + scrollX){
8218 x = swapX ? r.left-w : dw+scrollX-w;
8221 x = swapX ? r.right : scrollX;
8223 if((y+h) > dh + scrollY){
8224 y = swapY ? r.top-h : dh+scrollY-h;
8227 y = swapY ? r.bottom : scrollY;
8234 getConstrainToXY : function(){
8235 var os = {top:0, left:0, bottom:0, right: 0};
8237 return function(el, local, offsets, proposedXY){
8239 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8241 var vw, vh, vx = 0, vy = 0;
8242 if(el.dom == document.body || el.dom == document){
8243 vw = Roo.lib.Dom.getViewWidth();
8244 vh = Roo.lib.Dom.getViewHeight();
8246 vw = el.dom.clientWidth;
8247 vh = el.dom.clientHeight;
8249 var vxy = el.getXY();
8255 var s = el.getScroll();
8257 vx += offsets.left + s.left;
8258 vy += offsets.top + s.top;
8260 vw -= offsets.right;
8261 vh -= offsets.bottom;
8266 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8267 var x = xy[0], y = xy[1];
8268 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8270 // only move it if it needs it
8273 // first validate right/bottom
8282 // then make sure top/left isn't negative
8291 return moved ? [x, y] : false;
8296 adjustForConstraints : function(xy, parent, offsets){
8297 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8301 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8302 * document it aligns it to the viewport.
8303 * The position parameter is optional, and can be specified in any one of the following formats:
8305 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8306 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8307 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8308 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8309 * <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
8310 * element's anchor point, and the second value is used as the target's anchor point.</li>
8312 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8313 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8314 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8315 * that specified in order to enforce the viewport constraints.
8316 * Following are all of the supported anchor positions:
8319 ----- -----------------------------
8320 tl The top left corner (default)
8321 t The center of the top edge
8322 tr The top right corner
8323 l The center of the left edge
8324 c In the center of the element
8325 r The center of the right edge
8326 bl The bottom left corner
8327 b The center of the bottom edge
8328 br The bottom right corner
8332 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8333 el.alignTo("other-el");
8335 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8336 el.alignTo("other-el", "tr?");
8338 // align the bottom right corner of el with the center left edge of other-el
8339 el.alignTo("other-el", "br-l?");
8341 // align the center of el with the bottom left corner of other-el and
8342 // adjust the x position by -6 pixels (and the y position by 0)
8343 el.alignTo("other-el", "c-bl", [-6, 0]);
8345 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8346 * @param {String} position The position to align to.
8347 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8348 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8349 * @return {Roo.Element} this
8351 alignTo : function(element, position, offsets, animate){
8352 var xy = this.getAlignToXY(element, position, offsets);
8353 this.setXY(xy, this.preanim(arguments, 3));
8358 * Anchors an element to another element and realigns it when the window is resized.
8359 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8360 * @param {String} position The position to align to.
8361 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8362 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8363 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8364 * is a number, it is used as the buffer delay (defaults to 50ms).
8365 * @param {Function} callback The function to call after the animation finishes
8366 * @return {Roo.Element} this
8368 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8369 var action = function(){
8370 this.alignTo(el, alignment, offsets, animate);
8371 Roo.callback(callback, this);
8373 Roo.EventManager.onWindowResize(action, this);
8374 var tm = typeof monitorScroll;
8375 if(tm != 'undefined'){
8376 Roo.EventManager.on(window, 'scroll', action, this,
8377 {buffer: tm == 'number' ? monitorScroll : 50});
8379 action.call(this); // align immediately
8383 * Clears any opacity settings from this element. Required in some cases for IE.
8384 * @return {Roo.Element} this
8386 clearOpacity : function(){
8387 if (window.ActiveXObject) {
8388 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8389 this.dom.style.filter = "";
8392 this.dom.style.opacity = "";
8393 this.dom.style["-moz-opacity"] = "";
8394 this.dom.style["-khtml-opacity"] = "";
8400 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8401 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8402 * @return {Roo.Element} this
8404 hide : function(animate){
8405 this.setVisible(false, this.preanim(arguments, 0));
8410 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8411 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8412 * @return {Roo.Element} this
8414 show : function(animate){
8415 this.setVisible(true, this.preanim(arguments, 0));
8420 * @private Test if size has a unit, otherwise appends the default
8422 addUnits : function(size){
8423 return Roo.Element.addUnits(size, this.defaultUnit);
8427 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8428 * @return {Roo.Element} this
8430 beginMeasure : function(){
8432 if(el.offsetWidth || el.offsetHeight){
8433 return this; // offsets work already
8436 var p = this.dom, b = document.body; // start with this element
8437 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8438 var pe = Roo.get(p);
8439 if(pe.getStyle('display') == 'none'){
8440 changed.push({el: p, visibility: pe.getStyle("visibility")});
8441 p.style.visibility = "hidden";
8442 p.style.display = "block";
8446 this._measureChanged = changed;
8452 * Restores displays to before beginMeasure was called
8453 * @return {Roo.Element} this
8455 endMeasure : function(){
8456 var changed = this._measureChanged;
8458 for(var i = 0, len = changed.length; i < len; i++) {
8460 r.el.style.visibility = r.visibility;
8461 r.el.style.display = "none";
8463 this._measureChanged = null;
8469 * Update the innerHTML of this element, optionally searching for and processing scripts
8470 * @param {String} html The new HTML
8471 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8472 * @param {Function} callback For async script loading you can be noticed when the update completes
8473 * @return {Roo.Element} this
8475 update : function(html, loadScripts, callback){
8476 if(typeof html == "undefined"){
8479 if(loadScripts !== true){
8480 this.dom.innerHTML = html;
8481 if(typeof callback == "function"){
8489 html += '<span id="' + id + '"></span>';
8491 E.onAvailable(id, function(){
8492 var hd = document.getElementsByTagName("head")[0];
8493 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8494 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8495 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8498 while(match = re.exec(html)){
8499 var attrs = match[1];
8500 var srcMatch = attrs ? attrs.match(srcRe) : false;
8501 if(srcMatch && srcMatch[2]){
8502 var s = document.createElement("script");
8503 s.src = srcMatch[2];
8504 var typeMatch = attrs.match(typeRe);
8505 if(typeMatch && typeMatch[2]){
8506 s.type = typeMatch[2];
8509 }else if(match[2] && match[2].length > 0){
8510 if(window.execScript) {
8511 window.execScript(match[2]);
8519 window.eval(match[2]);
8523 var el = document.getElementById(id);
8524 if(el){el.parentNode.removeChild(el);}
8525 if(typeof callback == "function"){
8529 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8534 * Direct access to the UpdateManager update() method (takes the same parameters).
8535 * @param {String/Function} url The url for this request or a function to call to get the url
8536 * @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}
8537 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8538 * @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.
8539 * @return {Roo.Element} this
8542 var um = this.getUpdateManager();
8543 um.update.apply(um, arguments);
8548 * Gets this element's UpdateManager
8549 * @return {Roo.UpdateManager} The UpdateManager
8551 getUpdateManager : function(){
8552 if(!this.updateManager){
8553 this.updateManager = new Roo.UpdateManager(this);
8555 return this.updateManager;
8559 * Disables text selection for this element (normalized across browsers)
8560 * @return {Roo.Element} this
8562 unselectable : function(){
8563 this.dom.unselectable = "on";
8564 this.swallowEvent("selectstart", true);
8565 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8566 this.addClass("x-unselectable");
8571 * Calculates the x, y to center this element on the screen
8572 * @return {Array} The x, y values [x, y]
8574 getCenterXY : function(){
8575 return this.getAlignToXY(document, 'c-c');
8579 * Centers the Element in either the viewport, or another Element.
8580 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8582 center : function(centerIn){
8583 this.alignTo(centerIn || document, 'c-c');
8588 * Tests various css rules/browsers to determine if this element uses a border box
8591 isBorderBox : function(){
8592 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8596 * Return a box {x, y, width, height} that can be used to set another elements
8597 * size/location to match this element.
8598 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8599 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8600 * @return {Object} box An object in the format {x, y, width, height}
8602 getBox : function(contentBox, local){
8607 var left = parseInt(this.getStyle("left"), 10) || 0;
8608 var top = parseInt(this.getStyle("top"), 10) || 0;
8611 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8613 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8615 var l = this.getBorderWidth("l")+this.getPadding("l");
8616 var r = this.getBorderWidth("r")+this.getPadding("r");
8617 var t = this.getBorderWidth("t")+this.getPadding("t");
8618 var b = this.getBorderWidth("b")+this.getPadding("b");
8619 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)};
8621 bx.right = bx.x + bx.width;
8622 bx.bottom = bx.y + bx.height;
8627 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8628 for more information about the sides.
8629 * @param {String} sides
8632 getFrameWidth : function(sides, onlyContentBox){
8633 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8637 * 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.
8638 * @param {Object} box The box to fill {x, y, width, height}
8639 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8640 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8641 * @return {Roo.Element} this
8643 setBox : function(box, adjust, animate){
8644 var w = box.width, h = box.height;
8645 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8646 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8647 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8649 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8654 * Forces the browser to repaint this element
8655 * @return {Roo.Element} this
8657 repaint : function(){
8659 this.addClass("x-repaint");
8660 setTimeout(function(){
8661 Roo.get(dom).removeClass("x-repaint");
8667 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8668 * then it returns the calculated width of the sides (see getPadding)
8669 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8670 * @return {Object/Number}
8672 getMargins : function(side){
8675 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8676 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8677 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8678 right: parseInt(this.getStyle("margin-right"), 10) || 0
8681 return this.addStyles(side, El.margins);
8686 addStyles : function(sides, styles){
8688 for(var i = 0, len = sides.length; i < len; i++){
8689 v = this.getStyle(styles[sides.charAt(i)]);
8691 w = parseInt(v, 10);
8699 * Creates a proxy element of this element
8700 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8701 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8702 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8703 * @return {Roo.Element} The new proxy element
8705 createProxy : function(config, renderTo, matchBox){
8707 renderTo = Roo.getDom(renderTo);
8709 renderTo = document.body;
8711 config = typeof config == "object" ?
8712 config : {tag : "div", cls: config};
8713 var proxy = Roo.DomHelper.append(renderTo, config, true);
8715 proxy.setBox(this.getBox());
8721 * Puts a mask over this element to disable user interaction. Requires core.css.
8722 * This method can only be applied to elements which accept child nodes.
8723 * @param {String} msg (optional) A message to display in the mask
8724 * @param {String} msgCls (optional) A css class to apply to the msg element
8725 * @return {Element} The mask element
8727 mask : function(msg, msgCls){
8728 if(this.getStyle("position") == "static"){
8729 this.setStyle("position", "relative");
8732 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8734 this.addClass("x-masked");
8735 this._mask.setDisplayed(true);
8736 if(typeof msg == 'string'){
8738 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8740 var mm = this._maskMsg;
8741 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8742 mm.dom.firstChild.innerHTML = msg;
8743 mm.setDisplayed(true);
8746 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8747 this._mask.setHeight(this.getHeight());
8753 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8754 * it is cached for reuse.
8756 unmask : function(removeEl){
8758 if(removeEl === true){
8759 this._mask.remove();
8762 this._maskMsg.remove();
8763 delete this._maskMsg;
8766 this._mask.setDisplayed(false);
8768 this._maskMsg.setDisplayed(false);
8772 this.removeClass("x-masked");
8776 * Returns true if this element is masked
8779 isMasked : function(){
8780 return this._mask && this._mask.isVisible();
8784 * Creates an iframe shim for this element to keep selects and other windowed objects from
8786 * @return {Roo.Element} The new shim element
8788 createShim : function(){
8789 var el = document.createElement('iframe');
8790 el.frameBorder = 'no';
8791 el.className = 'roo-shim';
8792 if(Roo.isIE && Roo.isSecure){
8793 el.src = Roo.SSL_SECURE_URL;
8795 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8796 shim.autoBoxAdjust = false;
8801 * Removes this element from the DOM and deletes it from the cache
8803 remove : function(){
8804 if(this.dom.parentNode){
8805 this.dom.parentNode.removeChild(this.dom);
8807 delete El.cache[this.dom.id];
8811 * Sets up event handlers to add and remove a css class when the mouse is over this element
8812 * @param {String} className
8813 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8814 * mouseout events for children elements
8815 * @return {Roo.Element} this
8817 addClassOnOver : function(className, preventFlicker){
8818 this.on("mouseover", function(){
8819 Roo.fly(this, '_internal').addClass(className);
8821 var removeFn = function(e){
8822 if(preventFlicker !== true || !e.within(this, true)){
8823 Roo.fly(this, '_internal').removeClass(className);
8826 this.on("mouseout", removeFn, this.dom);
8831 * Sets up event handlers to add and remove a css class when this element has the focus
8832 * @param {String} className
8833 * @return {Roo.Element} this
8835 addClassOnFocus : function(className){
8836 this.on("focus", function(){
8837 Roo.fly(this, '_internal').addClass(className);
8839 this.on("blur", function(){
8840 Roo.fly(this, '_internal').removeClass(className);
8845 * 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)
8846 * @param {String} className
8847 * @return {Roo.Element} this
8849 addClassOnClick : function(className){
8851 this.on("mousedown", function(){
8852 Roo.fly(dom, '_internal').addClass(className);
8853 var d = Roo.get(document);
8854 var fn = function(){
8855 Roo.fly(dom, '_internal').removeClass(className);
8856 d.removeListener("mouseup", fn);
8858 d.on("mouseup", fn);
8864 * Stops the specified event from bubbling and optionally prevents the default action
8865 * @param {String} eventName
8866 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8867 * @return {Roo.Element} this
8869 swallowEvent : function(eventName, preventDefault){
8870 var fn = function(e){
8871 e.stopPropagation();
8876 if(eventName instanceof Array){
8877 for(var i = 0, len = eventName.length; i < len; i++){
8878 this.on(eventName[i], fn);
8882 this.on(eventName, fn);
8889 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8892 * Sizes this element to its parent element's dimensions performing
8893 * neccessary box adjustments.
8894 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8895 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8896 * @return {Roo.Element} this
8898 fitToParent : function(monitorResize, targetParent) {
8899 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8900 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8901 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8904 var p = Roo.get(targetParent || this.dom.parentNode);
8905 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8906 if (monitorResize === true) {
8907 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8908 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8914 * Gets the next sibling, skipping text nodes
8915 * @return {HTMLElement} The next sibling or null
8917 getNextSibling : function(){
8918 var n = this.dom.nextSibling;
8919 while(n && n.nodeType != 1){
8926 * Gets the previous sibling, skipping text nodes
8927 * @return {HTMLElement} The previous sibling or null
8929 getPrevSibling : function(){
8930 var n = this.dom.previousSibling;
8931 while(n && n.nodeType != 1){
8932 n = n.previousSibling;
8939 * Appends the passed element(s) to this element
8940 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8941 * @return {Roo.Element} this
8943 appendChild: function(el){
8950 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8951 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8952 * automatically generated with the specified attributes.
8953 * @param {HTMLElement} insertBefore (optional) a child element of this element
8954 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8955 * @return {Roo.Element} The new child element
8957 createChild: function(config, insertBefore, returnDom){
8958 config = config || {tag:'div'};
8960 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8962 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8966 * Appends this element to the passed element
8967 * @param {String/HTMLElement/Element} el The new parent element
8968 * @return {Roo.Element} this
8970 appendTo: function(el){
8971 el = Roo.getDom(el);
8972 el.appendChild(this.dom);
8977 * Inserts this element before the passed element in the DOM
8978 * @param {String/HTMLElement/Element} el The element to insert before
8979 * @return {Roo.Element} this
8981 insertBefore: function(el){
8982 el = Roo.getDom(el);
8983 el.parentNode.insertBefore(this.dom, el);
8988 * Inserts this element after the passed element in the DOM
8989 * @param {String/HTMLElement/Element} el The element to insert after
8990 * @return {Roo.Element} this
8992 insertAfter: function(el){
8993 el = Roo.getDom(el);
8994 el.parentNode.insertBefore(this.dom, el.nextSibling);
8999 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9000 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9001 * @return {Roo.Element} The new child
9003 insertFirst: function(el, returnDom){
9005 if(typeof el == 'object' && !el.nodeType){ // dh config
9006 return this.createChild(el, this.dom.firstChild, returnDom);
9008 el = Roo.getDom(el);
9009 this.dom.insertBefore(el, this.dom.firstChild);
9010 return !returnDom ? Roo.get(el) : el;
9015 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9016 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9017 * @param {String} where (optional) 'before' or 'after' defaults to before
9018 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9019 * @return {Roo.Element} the inserted Element
9021 insertSibling: function(el, where, returnDom){
9022 where = where ? where.toLowerCase() : 'before';
9024 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9026 if(typeof el == 'object' && !el.nodeType){ // dh config
9027 if(where == 'after' && !this.dom.nextSibling){
9028 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9030 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9034 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9035 where == 'before' ? this.dom : this.dom.nextSibling);
9044 * Creates and wraps this element with another element
9045 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9046 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9047 * @return {HTMLElement/Element} The newly created wrapper element
9049 wrap: function(config, returnDom){
9051 config = {tag: "div"};
9053 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9054 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9059 * Replaces the passed element with this element
9060 * @param {String/HTMLElement/Element} el The element to replace
9061 * @return {Roo.Element} this
9063 replace: function(el){
9065 this.insertBefore(el);
9071 * Inserts an html fragment into this element
9072 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9073 * @param {String} html The HTML fragment
9074 * @param {Boolean} returnEl True to return an Roo.Element
9075 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9077 insertHtml : function(where, html, returnEl){
9078 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9079 return returnEl ? Roo.get(el) : el;
9083 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9084 * @param {Object} o The object with the attributes
9085 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9086 * @return {Roo.Element} this
9088 set : function(o, useSet){
9090 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9092 if(attr == "style" || typeof o[attr] == "function") continue;
9094 el.className = o["cls"];
9096 if(useSet) el.setAttribute(attr, o[attr]);
9097 else el[attr] = o[attr];
9101 Roo.DomHelper.applyStyles(el, o.style);
9107 * Convenience method for constructing a KeyMap
9108 * @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:
9109 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9110 * @param {Function} fn The function to call
9111 * @param {Object} scope (optional) The scope of the function
9112 * @return {Roo.KeyMap} The KeyMap created
9114 addKeyListener : function(key, fn, scope){
9116 if(typeof key != "object" || key instanceof Array){
9132 return new Roo.KeyMap(this, config);
9136 * Creates a KeyMap for this element
9137 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9138 * @return {Roo.KeyMap} The KeyMap created
9140 addKeyMap : function(config){
9141 return new Roo.KeyMap(this, config);
9145 * Returns true if this element is scrollable.
9148 isScrollable : function(){
9150 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9154 * 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().
9155 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9156 * @param {Number} value The new scroll value
9157 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9158 * @return {Element} this
9161 scrollTo : function(side, value, animate){
9162 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9164 this.dom[prop] = value;
9166 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9167 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9173 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9174 * within this element's scrollable range.
9175 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9176 * @param {Number} distance How far to scroll the element in pixels
9177 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9178 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9179 * was scrolled as far as it could go.
9181 scroll : function(direction, distance, animate){
9182 if(!this.isScrollable()){
9186 var l = el.scrollLeft, t = el.scrollTop;
9187 var w = el.scrollWidth, h = el.scrollHeight;
9188 var cw = el.clientWidth, ch = el.clientHeight;
9189 direction = direction.toLowerCase();
9190 var scrolled = false;
9191 var a = this.preanim(arguments, 2);
9196 var v = Math.min(l + distance, w-cw);
9197 this.scrollTo("left", v, a);
9204 var v = Math.max(l - distance, 0);
9205 this.scrollTo("left", v, a);
9213 var v = Math.max(t - distance, 0);
9214 this.scrollTo("top", v, a);
9222 var v = Math.min(t + distance, h-ch);
9223 this.scrollTo("top", v, a);
9232 * Translates the passed page coordinates into left/top css values for this element
9233 * @param {Number/Array} x The page x or an array containing [x, y]
9234 * @param {Number} y The page y
9235 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9237 translatePoints : function(x, y){
9238 if(typeof x == 'object' || x instanceof Array){
9241 var p = this.getStyle('position');
9242 var o = this.getXY();
9244 var l = parseInt(this.getStyle('left'), 10);
9245 var t = parseInt(this.getStyle('top'), 10);
9248 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9251 t = (p == "relative") ? 0 : this.dom.offsetTop;
9254 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9258 * Returns the current scroll position of the element.
9259 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9261 getScroll : function(){
9262 var d = this.dom, doc = document;
9263 if(d == doc || d == doc.body){
9264 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9265 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9266 return {left: l, top: t};
9268 return {left: d.scrollLeft, top: d.scrollTop};
9273 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9274 * are convert to standard 6 digit hex color.
9275 * @param {String} attr The css attribute
9276 * @param {String} defaultValue The default value to use when a valid color isn't found
9277 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9280 getColor : function(attr, defaultValue, prefix){
9281 var v = this.getStyle(attr);
9282 if(!v || v == "transparent" || v == "inherit") {
9283 return defaultValue;
9285 var color = typeof prefix == "undefined" ? "#" : prefix;
9286 if(v.substr(0, 4) == "rgb("){
9287 var rvs = v.slice(4, v.length -1).split(",");
9288 for(var i = 0; i < 3; i++){
9289 var h = parseInt(rvs[i]).toString(16);
9296 if(v.substr(0, 1) == "#"){
9298 for(var i = 1; i < 4; i++){
9299 var c = v.charAt(i);
9302 }else if(v.length == 7){
9303 color += v.substr(1);
9307 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9311 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9312 * gradient background, rounded corners and a 4-way shadow.
9313 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9314 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9315 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9316 * @return {Roo.Element} this
9318 boxWrap : function(cls){
9319 cls = cls || 'x-box';
9320 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9321 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9326 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9327 * @param {String} namespace The namespace in which to look for the attribute
9328 * @param {String} name The attribute name
9329 * @return {String} The attribute value
9331 getAttributeNS : Roo.isIE ? function(ns, name){
9333 var type = typeof d[ns+":"+name];
9334 if(type != 'undefined' && type != 'unknown'){
9335 return d[ns+":"+name];
9338 } : function(ns, name){
9340 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9344 var ep = El.prototype;
9347 * Appends an event handler (Shorthand for addListener)
9348 * @param {String} eventName The type of event to append
9349 * @param {Function} fn The method the event invokes
9350 * @param {Object} scope (optional) The scope (this object) of the fn
9351 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9354 ep.on = ep.addListener;
9356 ep.mon = ep.addListener;
9359 * Removes an event handler from this element (shorthand for removeListener)
9360 * @param {String} eventName the type of event to remove
9361 * @param {Function} fn the method the event invokes
9362 * @return {Roo.Element} this
9365 ep.un = ep.removeListener;
9368 * true to automatically adjust width and height settings for box-model issues (default to true)
9370 ep.autoBoxAdjust = true;
9373 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9376 El.addUnits = function(v, defaultUnit){
9377 if(v === "" || v == "auto"){
9380 if(v === undefined){
9383 if(typeof v == "number" || !El.unitPattern.test(v)){
9384 return v + (defaultUnit || 'px');
9389 // special markup used throughout Roo when box wrapping elements
9390 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>';
9392 * Visibility mode constant - Use visibility to hide element
9398 * Visibility mode constant - Use display to hide element
9404 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9405 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9406 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9418 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9419 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9420 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9421 * @return {Element} The Element object
9424 El.get = function(el){
9426 if(!el){ return null; }
9427 if(typeof el == "string"){ // element id
9428 if(!(elm = document.getElementById(el))){
9431 if(ex = El.cache[el]){
9434 ex = El.cache[el] = new El(elm);
9437 }else if(el.tagName){ // dom element
9441 if(ex = El.cache[id]){
9444 ex = El.cache[id] = new El(el);
9447 }else if(el instanceof El){
9449 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9450 // catch case where it hasn't been appended
9451 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9454 }else if(el.isComposite){
9456 }else if(el instanceof Array){
9457 return El.select(el);
9458 }else if(el == document){
9459 // create a bogus element object representing the document object
9461 var f = function(){};
9462 f.prototype = El.prototype;
9464 docEl.dom = document;
9472 El.uncache = function(el){
9473 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9475 delete El.cache[a[i].id || a[i]];
9481 // Garbage collection - uncache elements/purge listeners on orphaned elements
9482 // so we don't hold a reference and cause the browser to retain them
9483 El.garbageCollect = function(){
9484 if(!Roo.enableGarbageCollector){
9485 clearInterval(El.collectorThread);
9488 for(var eid in El.cache){
9489 var el = El.cache[eid], d = el.dom;
9490 // -------------------------------------------------------
9491 // Determining what is garbage:
9492 // -------------------------------------------------------
9494 // dom node is null, definitely garbage
9495 // -------------------------------------------------------
9497 // no parentNode == direct orphan, definitely garbage
9498 // -------------------------------------------------------
9499 // !d.offsetParent && !document.getElementById(eid)
9500 // display none elements have no offsetParent so we will
9501 // also try to look it up by it's id. However, check
9502 // offsetParent first so we don't do unneeded lookups.
9503 // This enables collection of elements that are not orphans
9504 // directly, but somewhere up the line they have an orphan
9506 // -------------------------------------------------------
9507 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9508 delete El.cache[eid];
9509 if(d && Roo.enableListenerCollection){
9515 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9519 El.Flyweight = function(dom){
9522 El.Flyweight.prototype = El.prototype;
9524 El._flyweights = {};
9526 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9527 * the dom node can be overwritten by other code.
9528 * @param {String/HTMLElement} el The dom node or id
9529 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9530 * prevent conflicts (e.g. internally Roo uses "_internal")
9532 * @return {Element} The shared Element object
9534 El.fly = function(el, named){
9535 named = named || '_global';
9536 el = Roo.getDom(el);
9540 if(!El._flyweights[named]){
9541 El._flyweights[named] = new El.Flyweight();
9543 El._flyweights[named].dom = el;
9544 return El._flyweights[named];
9548 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9549 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9550 * Shorthand of {@link Roo.Element#get}
9551 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9552 * @return {Element} The Element object
9558 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9559 * the dom node can be overwritten by other code.
9560 * Shorthand of {@link Roo.Element#fly}
9561 * @param {String/HTMLElement} el The dom node or id
9562 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9563 * prevent conflicts (e.g. internally Roo uses "_internal")
9565 * @return {Element} The shared Element object
9571 // speedy lookup for elements never to box adjust
9572 var noBoxAdjust = Roo.isStrict ? {
9575 input:1, select:1, textarea:1
9577 if(Roo.isIE || Roo.isGecko){
9578 noBoxAdjust['button'] = 1;
9582 Roo.EventManager.on(window, 'unload', function(){
9584 delete El._flyweights;
9592 Roo.Element.selectorFunction = Roo.DomQuery.select;
9595 Roo.Element.select = function(selector, unique, root){
9597 if(typeof selector == "string"){
9598 els = Roo.Element.selectorFunction(selector, root);
9599 }else if(selector.length !== undefined){
9602 throw "Invalid selector";
9604 if(unique === true){
9605 return new Roo.CompositeElement(els);
9607 return new Roo.CompositeElementLite(els);
9611 * Selects elements based on the passed CSS selector to enable working on them as 1.
9612 * @param {String/Array} selector The CSS selector or an array of elements
9613 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9614 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9615 * @return {CompositeElementLite/CompositeElement}
9619 Roo.select = Roo.Element.select;
9636 * Ext JS Library 1.1.1
9637 * Copyright(c) 2006-2007, Ext JS, LLC.
9639 * Originally Released Under LGPL - original licence link has changed is not relivant.
9642 * <script type="text/javascript">
9647 //Notifies Element that fx methods are available
9648 Roo.enableFx = true;
9652 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9653 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9654 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9655 * Element effects to work.</p><br/>
9657 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9658 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9659 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9660 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9661 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9662 * expected results and should be done with care.</p><br/>
9664 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9665 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9668 ----- -----------------------------
9669 tl The top left corner
9670 t The center of the top edge
9671 tr The top right corner
9672 l The center of the left edge
9673 r The center of the right edge
9674 bl The bottom left corner
9675 b The center of the bottom edge
9676 br The bottom right corner
9678 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9679 * below are common options that can be passed to any Fx method.</b>
9680 * @cfg {Function} callback A function called when the effect is finished
9681 * @cfg {Object} scope The scope of the effect function
9682 * @cfg {String} easing A valid Easing value for the effect
9683 * @cfg {String} afterCls A css class to apply after the effect
9684 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9685 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9686 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9687 * effects that end with the element being visually hidden, ignored otherwise)
9688 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9689 * a function which returns such a specification that will be applied to the Element after the effect finishes
9690 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9691 * @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
9692 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9696 * Slides the element into view. An anchor point can be optionally passed to set the point of
9697 * origin for the slide effect. This function automatically handles wrapping the element with
9698 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9701 // default: slide the element in from the top
9704 // custom: slide the element in from the right with a 2-second duration
9705 el.slideIn('r', { duration: 2 });
9707 // common config options shown with default values
9713 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9714 * @param {Object} options (optional) Object literal with any of the Fx config options
9715 * @return {Roo.Element} The Element
9717 slideIn : function(anchor, o){
9718 var el = this.getFxEl();
9721 el.queueFx(o, function(){
9723 anchor = anchor || "t";
9725 // fix display to visibility
9728 // restore values after effect
9729 var r = this.getFxRestore();
9730 var b = this.getBox();
9731 // fixed size for slide
9735 var wrap = this.fxWrap(r.pos, o, "hidden");
9737 var st = this.dom.style;
9738 st.visibility = "visible";
9739 st.position = "absolute";
9741 // clear out temp styles after slide and unwrap
9742 var after = function(){
9743 el.fxUnwrap(wrap, r.pos, o);
9745 st.height = r.height;
9748 // time to calc the positions
9749 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9751 switch(anchor.toLowerCase()){
9753 wrap.setSize(b.width, 0);
9754 st.left = st.bottom = "0";
9758 wrap.setSize(0, b.height);
9759 st.right = st.top = "0";
9763 wrap.setSize(0, b.height);
9765 st.left = st.top = "0";
9766 a = {width: bw, points: pt};
9769 wrap.setSize(b.width, 0);
9770 wrap.setY(b.bottom);
9771 st.left = st.top = "0";
9772 a = {height: bh, points: pt};
9776 st.right = st.bottom = "0";
9777 a = {width: bw, height: bh};
9781 wrap.setY(b.y+b.height);
9782 st.right = st.top = "0";
9783 a = {width: bw, height: bh, points: pt};
9787 wrap.setXY([b.right, b.bottom]);
9788 st.left = st.top = "0";
9789 a = {width: bw, height: bh, points: pt};
9793 wrap.setX(b.x+b.width);
9794 st.left = st.bottom = "0";
9795 a = {width: bw, height: bh, points: pt};
9798 this.dom.style.visibility = "visible";
9801 arguments.callee.anim = wrap.fxanim(a,
9811 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9812 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9813 * 'hidden') but block elements will still take up space in the document. The element must be removed
9814 * from the DOM using the 'remove' config option if desired. This function automatically handles
9815 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9818 // default: slide the element out to the top
9821 // custom: slide the element out to the right with a 2-second duration
9822 el.slideOut('r', { duration: 2 });
9824 // common config options shown with default values
9832 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9833 * @param {Object} options (optional) Object literal with any of the Fx config options
9834 * @return {Roo.Element} The Element
9836 slideOut : function(anchor, o){
9837 var el = this.getFxEl();
9840 el.queueFx(o, function(){
9842 anchor = anchor || "t";
9844 // restore values after effect
9845 var r = this.getFxRestore();
9847 var b = this.getBox();
9848 // fixed size for slide
9852 var wrap = this.fxWrap(r.pos, o, "visible");
9854 var st = this.dom.style;
9855 st.visibility = "visible";
9856 st.position = "absolute";
9860 var after = function(){
9862 el.setDisplayed(false);
9867 el.fxUnwrap(wrap, r.pos, o);
9870 st.height = r.height;
9875 var a, zero = {to: 0};
9876 switch(anchor.toLowerCase()){
9878 st.left = st.bottom = "0";
9882 st.right = st.top = "0";
9886 st.left = st.top = "0";
9887 a = {width: zero, points: {to:[b.right, b.y]}};
9890 st.left = st.top = "0";
9891 a = {height: zero, points: {to:[b.x, b.bottom]}};
9894 st.right = st.bottom = "0";
9895 a = {width: zero, height: zero};
9898 st.right = st.top = "0";
9899 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9902 st.left = st.top = "0";
9903 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9906 st.left = st.bottom = "0";
9907 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9911 arguments.callee.anim = wrap.fxanim(a,
9921 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9922 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9923 * The element must be removed from the DOM using the 'remove' config option if desired.
9929 // common config options shown with default values
9937 * @param {Object} options (optional) Object literal with any of the Fx config options
9938 * @return {Roo.Element} The Element
9941 var el = this.getFxEl();
9944 el.queueFx(o, function(){
9945 this.clearOpacity();
9948 // restore values after effect
9949 var r = this.getFxRestore();
9950 var st = this.dom.style;
9952 var after = function(){
9954 el.setDisplayed(false);
9961 el.setPositioning(r.pos);
9963 st.height = r.height;
9968 var width = this.getWidth();
9969 var height = this.getHeight();
9971 arguments.callee.anim = this.fxanim({
9972 width : {to: this.adjustWidth(width * 2)},
9973 height : {to: this.adjustHeight(height * 2)},
9974 points : {by: [-(width * .5), -(height * .5)]},
9976 fontSize: {to:200, unit: "%"}
9987 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9988 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
9989 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9995 // all config options shown with default values
10003 * @param {Object} options (optional) Object literal with any of the Fx config options
10004 * @return {Roo.Element} The Element
10006 switchOff : function(o){
10007 var el = this.getFxEl();
10010 el.queueFx(o, function(){
10011 this.clearOpacity();
10014 // restore values after effect
10015 var r = this.getFxRestore();
10016 var st = this.dom.style;
10018 var after = function(){
10020 el.setDisplayed(false);
10026 el.setPositioning(r.pos);
10027 st.width = r.width;
10028 st.height = r.height;
10033 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10034 this.clearOpacity();
10038 points:{by:[0, this.getHeight() * .5]}
10039 }, o, 'motion', 0.3, 'easeIn', after);
10040 }).defer(100, this);
10047 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10048 * changed using the "attr" config option) and then fading back to the original color. If no original
10049 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10052 // default: highlight background to yellow
10055 // custom: highlight foreground text to blue for 2 seconds
10056 el.highlight("0000ff", { attr: 'color', duration: 2 });
10058 // common config options shown with default values
10059 el.highlight("ffff9c", {
10060 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10061 endColor: (current color) or "ffffff",
10066 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10067 * @param {Object} options (optional) Object literal with any of the Fx config options
10068 * @return {Roo.Element} The Element
10070 highlight : function(color, o){
10071 var el = this.getFxEl();
10074 el.queueFx(o, function(){
10075 color = color || "ffff9c";
10076 attr = o.attr || "backgroundColor";
10078 this.clearOpacity();
10081 var origColor = this.getColor(attr);
10082 var restoreColor = this.dom.style[attr];
10083 endColor = (o.endColor || origColor) || "ffffff";
10085 var after = function(){
10086 el.dom.style[attr] = restoreColor;
10091 a[attr] = {from: color, to: endColor};
10092 arguments.callee.anim = this.fxanim(a,
10102 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10105 // default: a single light blue ripple
10108 // custom: 3 red ripples lasting 3 seconds total
10109 el.frame("ff0000", 3, { duration: 3 });
10111 // common config options shown with default values
10112 el.frame("C3DAF9", 1, {
10113 duration: 1 //duration of entire animation (not each individual ripple)
10114 // Note: Easing is not configurable and will be ignored if included
10117 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10118 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10119 * @param {Object} options (optional) Object literal with any of the Fx config options
10120 * @return {Roo.Element} The Element
10122 frame : function(color, count, o){
10123 var el = this.getFxEl();
10126 el.queueFx(o, function(){
10127 color = color || "#C3DAF9";
10128 if(color.length == 6){
10129 color = "#" + color;
10131 count = count || 1;
10132 duration = o.duration || 1;
10135 var b = this.getBox();
10136 var animFn = function(){
10137 var proxy = this.createProxy({
10140 visbility:"hidden",
10141 position:"absolute",
10142 "z-index":"35000", // yee haw
10143 border:"0px solid " + color
10146 var scale = Roo.isBorderBox ? 2 : 1;
10148 top:{from:b.y, to:b.y - 20},
10149 left:{from:b.x, to:b.x - 20},
10150 borderWidth:{from:0, to:10},
10151 opacity:{from:1, to:0},
10152 height:{from:b.height, to:(b.height + (20*scale))},
10153 width:{from:b.width, to:(b.width + (20*scale))}
10154 }, duration, function(){
10158 animFn.defer((duration/2)*1000, this);
10169 * Creates a pause before any subsequent queued effects begin. If there are
10170 * no effects queued after the pause it will have no effect.
10175 * @param {Number} seconds The length of time to pause (in seconds)
10176 * @return {Roo.Element} The Element
10178 pause : function(seconds){
10179 var el = this.getFxEl();
10182 el.queueFx(o, function(){
10183 setTimeout(function(){
10185 }, seconds * 1000);
10191 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10192 * using the "endOpacity" config option.
10195 // default: fade in from opacity 0 to 100%
10198 // custom: fade in from opacity 0 to 75% over 2 seconds
10199 el.fadeIn({ endOpacity: .75, duration: 2});
10201 // common config options shown with default values
10203 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10208 * @param {Object} options (optional) Object literal with any of the Fx config options
10209 * @return {Roo.Element} The Element
10211 fadeIn : function(o){
10212 var el = this.getFxEl();
10214 el.queueFx(o, function(){
10215 this.setOpacity(0);
10217 this.dom.style.visibility = 'visible';
10218 var to = o.endOpacity || 1;
10219 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10220 o, null, .5, "easeOut", function(){
10222 this.clearOpacity();
10231 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10232 * using the "endOpacity" config option.
10235 // default: fade out from the element's current opacity to 0
10238 // custom: fade out from the element's current opacity to 25% over 2 seconds
10239 el.fadeOut({ endOpacity: .25, duration: 2});
10241 // common config options shown with default values
10243 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10250 * @param {Object} options (optional) Object literal with any of the Fx config options
10251 * @return {Roo.Element} The Element
10253 fadeOut : function(o){
10254 var el = this.getFxEl();
10256 el.queueFx(o, function(){
10257 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10258 o, null, .5, "easeOut", function(){
10259 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10260 this.dom.style.display = "none";
10262 this.dom.style.visibility = "hidden";
10264 this.clearOpacity();
10272 * Animates the transition of an element's dimensions from a starting height/width
10273 * to an ending height/width.
10276 // change height and width to 100x100 pixels
10277 el.scale(100, 100);
10279 // common config options shown with default values. The height and width will default to
10280 // the element's existing values if passed as null.
10283 [element's height], {
10288 * @param {Number} width The new width (pass undefined to keep the original width)
10289 * @param {Number} height The new height (pass undefined to keep the original height)
10290 * @param {Object} options (optional) Object literal with any of the Fx config options
10291 * @return {Roo.Element} The Element
10293 scale : function(w, h, o){
10294 this.shift(Roo.apply({}, o, {
10302 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10303 * Any of these properties not specified in the config object will not be changed. This effect
10304 * requires that at least one new dimension, position or opacity setting must be passed in on
10305 * the config object in order for the function to have any effect.
10308 // slide the element horizontally to x position 200 while changing the height and opacity
10309 el.shift({ x: 200, height: 50, opacity: .8 });
10311 // common config options shown with default values.
10313 width: [element's width],
10314 height: [element's height],
10315 x: [element's x position],
10316 y: [element's y position],
10317 opacity: [element's opacity],
10322 * @param {Object} options Object literal with any of the Fx config options
10323 * @return {Roo.Element} The Element
10325 shift : function(o){
10326 var el = this.getFxEl();
10328 el.queueFx(o, function(){
10329 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10330 if(w !== undefined){
10331 a.width = {to: this.adjustWidth(w)};
10333 if(h !== undefined){
10334 a.height = {to: this.adjustHeight(h)};
10336 if(x !== undefined || y !== undefined){
10338 x !== undefined ? x : this.getX(),
10339 y !== undefined ? y : this.getY()
10342 if(op !== undefined){
10343 a.opacity = {to: op};
10345 if(o.xy !== undefined){
10346 a.points = {to: o.xy};
10348 arguments.callee.anim = this.fxanim(a,
10349 o, 'motion', .35, "easeOut", function(){
10357 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10358 * ending point of the effect.
10361 // default: slide the element downward while fading out
10364 // custom: slide the element out to the right with a 2-second duration
10365 el.ghost('r', { duration: 2 });
10367 // common config options shown with default values
10375 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10376 * @param {Object} options (optional) Object literal with any of the Fx config options
10377 * @return {Roo.Element} The Element
10379 ghost : function(anchor, o){
10380 var el = this.getFxEl();
10383 el.queueFx(o, function(){
10384 anchor = anchor || "b";
10386 // restore values after effect
10387 var r = this.getFxRestore();
10388 var w = this.getWidth(),
10389 h = this.getHeight();
10391 var st = this.dom.style;
10393 var after = function(){
10395 el.setDisplayed(false);
10401 el.setPositioning(r.pos);
10402 st.width = r.width;
10403 st.height = r.height;
10408 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10409 switch(anchor.toLowerCase()){
10436 arguments.callee.anim = this.fxanim(a,
10446 * Ensures that all effects queued after syncFx is called on the element are
10447 * run concurrently. This is the opposite of {@link #sequenceFx}.
10448 * @return {Roo.Element} The Element
10450 syncFx : function(){
10451 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10460 * Ensures that all effects queued after sequenceFx is called on the element are
10461 * run in sequence. This is the opposite of {@link #syncFx}.
10462 * @return {Roo.Element} The Element
10464 sequenceFx : function(){
10465 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10467 concurrent : false,
10474 nextFx : function(){
10475 var ef = this.fxQueue[0];
10482 * Returns true if the element has any effects actively running or queued, else returns false.
10483 * @return {Boolean} True if element has active effects, else false
10485 hasActiveFx : function(){
10486 return this.fxQueue && this.fxQueue[0];
10490 * Stops any running effects and clears the element's internal effects queue if it contains
10491 * any additional effects that haven't started yet.
10492 * @return {Roo.Element} The Element
10494 stopFx : function(){
10495 if(this.hasActiveFx()){
10496 var cur = this.fxQueue[0];
10497 if(cur && cur.anim && cur.anim.isAnimated()){
10498 this.fxQueue = [cur]; // clear out others
10499 cur.anim.stop(true);
10506 beforeFx : function(o){
10507 if(this.hasActiveFx() && !o.concurrent){
10518 * Returns true if the element is currently blocking so that no other effect can be queued
10519 * until this effect is finished, else returns false if blocking is not set. This is commonly
10520 * used to ensure that an effect initiated by a user action runs to completion prior to the
10521 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10522 * @return {Boolean} True if blocking, else false
10524 hasFxBlock : function(){
10525 var q = this.fxQueue;
10526 return q && q[0] && q[0].block;
10530 queueFx : function(o, fn){
10534 if(!this.hasFxBlock()){
10535 Roo.applyIf(o, this.fxDefaults);
10537 var run = this.beforeFx(o);
10538 fn.block = o.block;
10539 this.fxQueue.push(fn);
10551 fxWrap : function(pos, o, vis){
10553 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10556 wrapXY = this.getXY();
10558 var div = document.createElement("div");
10559 div.style.visibility = vis;
10560 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10561 wrap.setPositioning(pos);
10562 if(wrap.getStyle("position") == "static"){
10563 wrap.position("relative");
10565 this.clearPositioning('auto');
10567 wrap.dom.appendChild(this.dom);
10569 wrap.setXY(wrapXY);
10576 fxUnwrap : function(wrap, pos, o){
10577 this.clearPositioning();
10578 this.setPositioning(pos);
10580 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10586 getFxRestore : function(){
10587 var st = this.dom.style;
10588 return {pos: this.getPositioning(), width: st.width, height : st.height};
10592 afterFx : function(o){
10594 this.applyStyles(o.afterStyle);
10597 this.addClass(o.afterCls);
10599 if(o.remove === true){
10602 Roo.callback(o.callback, o.scope, [this]);
10604 this.fxQueue.shift();
10610 getFxEl : function(){ // support for composite element fx
10611 return Roo.get(this.dom);
10615 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10616 animType = animType || 'run';
10618 var anim = Roo.lib.Anim[animType](
10620 (opt.duration || defaultDur) || .35,
10621 (opt.easing || defaultEase) || 'easeOut',
10623 Roo.callback(cb, this);
10632 // backwords compat
10633 Roo.Fx.resize = Roo.Fx.scale;
10635 //When included, Roo.Fx is automatically applied to Element so that all basic
10636 //effects are available directly via the Element API
10637 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10639 * Ext JS Library 1.1.1
10640 * Copyright(c) 2006-2007, Ext JS, LLC.
10642 * Originally Released Under LGPL - original licence link has changed is not relivant.
10645 * <script type="text/javascript">
10650 * @class Roo.CompositeElement
10651 * Standard composite class. Creates a Roo.Element for every element in the collection.
10653 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10654 * actions will be performed on all the elements in this collection.</b>
10656 * All methods return <i>this</i> and can be chained.
10658 var els = Roo.select("#some-el div.some-class", true);
10659 // or select directly from an existing element
10660 var el = Roo.get('some-el');
10661 el.select('div.some-class', true);
10663 els.setWidth(100); // all elements become 100 width
10664 els.hide(true); // all elements fade out and hide
10666 els.setWidth(100).hide(true);
10669 Roo.CompositeElement = function(els){
10670 this.elements = [];
10671 this.addElements(els);
10673 Roo.CompositeElement.prototype = {
10675 addElements : function(els){
10676 if(!els) return this;
10677 if(typeof els == "string"){
10678 els = Roo.Element.selectorFunction(els);
10680 var yels = this.elements;
10681 var index = yels.length-1;
10682 for(var i = 0, len = els.length; i < len; i++) {
10683 yels[++index] = Roo.get(els[i]);
10689 * Clears this composite and adds the elements returned by the passed selector.
10690 * @param {String/Array} els A string CSS selector, an array of elements or an element
10691 * @return {CompositeElement} this
10693 fill : function(els){
10694 this.elements = [];
10700 * Filters this composite to only elements that match the passed selector.
10701 * @param {String} selector A string CSS selector
10702 * @return {CompositeElement} this
10704 filter : function(selector){
10706 this.each(function(el){
10707 if(el.is(selector)){
10708 els[els.length] = el.dom;
10715 invoke : function(fn, args){
10716 var els = this.elements;
10717 for(var i = 0, len = els.length; i < len; i++) {
10718 Roo.Element.prototype[fn].apply(els[i], args);
10723 * Adds elements to this composite.
10724 * @param {String/Array} els A string CSS selector, an array of elements or an element
10725 * @return {CompositeElement} this
10727 add : function(els){
10728 if(typeof els == "string"){
10729 this.addElements(Roo.Element.selectorFunction(els));
10730 }else if(els.length !== undefined){
10731 this.addElements(els);
10733 this.addElements([els]);
10738 * Calls the passed function passing (el, this, index) for each element in this composite.
10739 * @param {Function} fn The function to call
10740 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10741 * @return {CompositeElement} this
10743 each : function(fn, scope){
10744 var els = this.elements;
10745 for(var i = 0, len = els.length; i < len; i++){
10746 if(fn.call(scope || els[i], els[i], this, i) === false) {
10754 * Returns the Element object at the specified index
10755 * @param {Number} index
10756 * @return {Roo.Element}
10758 item : function(index){
10759 return this.elements[index] || null;
10763 * Returns the first Element
10764 * @return {Roo.Element}
10766 first : function(){
10767 return this.item(0);
10771 * Returns the last Element
10772 * @return {Roo.Element}
10775 return this.item(this.elements.length-1);
10779 * Returns the number of elements in this composite
10782 getCount : function(){
10783 return this.elements.length;
10787 * Returns true if this composite contains the passed element
10790 contains : function(el){
10791 return this.indexOf(el) !== -1;
10795 * Returns true if this composite contains the passed element
10798 indexOf : function(el){
10799 return this.elements.indexOf(Roo.get(el));
10804 * Removes the specified element(s).
10805 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10806 * or an array of any of those.
10807 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10808 * @return {CompositeElement} this
10810 removeElement : function(el, removeDom){
10811 if(el instanceof Array){
10812 for(var i = 0, len = el.length; i < len; i++){
10813 this.removeElement(el[i]);
10817 var index = typeof el == 'number' ? el : this.indexOf(el);
10820 var d = this.elements[index];
10824 d.parentNode.removeChild(d);
10827 this.elements.splice(index, 1);
10833 * Replaces the specified element with the passed element.
10834 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10836 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10837 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10838 * @return {CompositeElement} this
10840 replaceElement : function(el, replacement, domReplace){
10841 var index = typeof el == 'number' ? el : this.indexOf(el);
10844 this.elements[index].replaceWith(replacement);
10846 this.elements.splice(index, 1, Roo.get(replacement))
10853 * Removes all elements.
10855 clear : function(){
10856 this.elements = [];
10860 Roo.CompositeElement.createCall = function(proto, fnName){
10861 if(!proto[fnName]){
10862 proto[fnName] = function(){
10863 return this.invoke(fnName, arguments);
10867 for(var fnName in Roo.Element.prototype){
10868 if(typeof Roo.Element.prototype[fnName] == "function"){
10869 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10875 * Ext JS Library 1.1.1
10876 * Copyright(c) 2006-2007, Ext JS, LLC.
10878 * Originally Released Under LGPL - original licence link has changed is not relivant.
10881 * <script type="text/javascript">
10885 * @class Roo.CompositeElementLite
10886 * @extends Roo.CompositeElement
10887 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10889 var els = Roo.select("#some-el div.some-class");
10890 // or select directly from an existing element
10891 var el = Roo.get('some-el');
10892 el.select('div.some-class');
10894 els.setWidth(100); // all elements become 100 width
10895 els.hide(true); // all elements fade out and hide
10897 els.setWidth(100).hide(true);
10898 </code></pre><br><br>
10899 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10900 * actions will be performed on all the elements in this collection.</b>
10902 Roo.CompositeElementLite = function(els){
10903 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10904 this.el = new Roo.Element.Flyweight();
10906 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10907 addElements : function(els){
10909 if(els instanceof Array){
10910 this.elements = this.elements.concat(els);
10912 var yels = this.elements;
10913 var index = yels.length-1;
10914 for(var i = 0, len = els.length; i < len; i++) {
10915 yels[++index] = els[i];
10921 invoke : function(fn, args){
10922 var els = this.elements;
10924 for(var i = 0, len = els.length; i < len; i++) {
10926 Roo.Element.prototype[fn].apply(el, args);
10931 * Returns a flyweight Element of the dom element object at the specified index
10932 * @param {Number} index
10933 * @return {Roo.Element}
10935 item : function(index){
10936 if(!this.elements[index]){
10939 this.el.dom = this.elements[index];
10943 // fixes scope with flyweight
10944 addListener : function(eventName, handler, scope, opt){
10945 var els = this.elements;
10946 for(var i = 0, len = els.length; i < len; i++) {
10947 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10953 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10954 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10955 * a reference to the dom node, use el.dom.</b>
10956 * @param {Function} fn The function to call
10957 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10958 * @return {CompositeElement} this
10960 each : function(fn, scope){
10961 var els = this.elements;
10963 for(var i = 0, len = els.length; i < len; i++){
10965 if(fn.call(scope || el, el, this, i) === false){
10972 indexOf : function(el){
10973 return this.elements.indexOf(Roo.getDom(el));
10976 replaceElement : function(el, replacement, domReplace){
10977 var index = typeof el == 'number' ? el : this.indexOf(el);
10979 replacement = Roo.getDom(replacement);
10981 var d = this.elements[index];
10982 d.parentNode.insertBefore(replacement, d);
10983 d.parentNode.removeChild(d);
10985 this.elements.splice(index, 1, replacement);
10990 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10994 * Ext JS Library 1.1.1
10995 * Copyright(c) 2006-2007, Ext JS, LLC.
10997 * Originally Released Under LGPL - original licence link has changed is not relivant.
11000 * <script type="text/javascript">
11006 * @class Roo.data.Connection
11007 * @extends Roo.util.Observable
11008 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11009 * either to a configured URL, or to a URL specified at request time.<br><br>
11011 * Requests made by this class are asynchronous, and will return immediately. No data from
11012 * the server will be available to the statement immediately following the {@link #request} call.
11013 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11015 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11016 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11017 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11018 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11019 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11020 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11021 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11022 * standard DOM methods.
11024 * @param {Object} config a configuration object.
11026 Roo.data.Connection = function(config){
11027 Roo.apply(this, config);
11030 * @event beforerequest
11031 * Fires before a network request is made to retrieve a data object.
11032 * @param {Connection} conn This Connection object.
11033 * @param {Object} options The options config object passed to the {@link #request} method.
11035 "beforerequest" : true,
11037 * @event requestcomplete
11038 * Fires if the request was successfully completed.
11039 * @param {Connection} conn This Connection object.
11040 * @param {Object} response The XHR object containing the response data.
11041 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11042 * @param {Object} options The options config object passed to the {@link #request} method.
11044 "requestcomplete" : true,
11046 * @event requestexception
11047 * Fires if an error HTTP status was returned from the server.
11048 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11049 * @param {Connection} conn This Connection object.
11050 * @param {Object} response The XHR object containing the response data.
11051 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11052 * @param {Object} options The options config object passed to the {@link #request} method.
11054 "requestexception" : true
11056 Roo.data.Connection.superclass.constructor.call(this);
11059 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11061 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11064 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11065 * extra parameters to each request made by this object. (defaults to undefined)
11068 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11069 * to each request made by this object. (defaults to undefined)
11072 * @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)
11075 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11079 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11085 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11088 disableCaching: true,
11091 * Sends an HTTP request to a remote server.
11092 * @param {Object} options An object which may contain the following properties:<ul>
11093 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11094 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11095 * request, a url encoded string or a function to call to get either.</li>
11096 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11097 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11098 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11099 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11100 * <li>options {Object} The parameter to the request call.</li>
11101 * <li>success {Boolean} True if the request succeeded.</li>
11102 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11104 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11105 * The callback is passed the following parameters:<ul>
11106 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11107 * <li>options {Object} The parameter to the request call.</li>
11109 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11110 * The callback is passed the following parameters:<ul>
11111 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11112 * <li>options {Object} The parameter to the request call.</li>
11114 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11115 * for the callback function. Defaults to the browser window.</li>
11116 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11117 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11118 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11119 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11120 * params for the post data. Any params will be appended to the URL.</li>
11121 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11123 * @return {Number} transactionId
11125 request : function(o){
11126 if(this.fireEvent("beforerequest", this, o) !== false){
11129 if(typeof p == "function"){
11130 p = p.call(o.scope||window, o);
11132 if(typeof p == "object"){
11133 p = Roo.urlEncode(o.params);
11135 if(this.extraParams){
11136 var extras = Roo.urlEncode(this.extraParams);
11137 p = p ? (p + '&' + extras) : extras;
11140 var url = o.url || this.url;
11141 if(typeof url == 'function'){
11142 url = url.call(o.scope||window, o);
11146 var form = Roo.getDom(o.form);
11147 url = url || form.action;
11149 var enctype = form.getAttribute("enctype");
11150 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11151 return this.doFormUpload(o, p, url);
11153 var f = Roo.lib.Ajax.serializeForm(form);
11154 p = p ? (p + '&' + f) : f;
11157 var hs = o.headers;
11158 if(this.defaultHeaders){
11159 hs = Roo.apply(hs || {}, this.defaultHeaders);
11166 success: this.handleResponse,
11167 failure: this.handleFailure,
11169 argument: {options: o},
11170 timeout : this.timeout
11173 var method = o.method||this.method||(p ? "POST" : "GET");
11175 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11176 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11179 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11183 }else if(this.autoAbort !== false){
11187 if((method == 'GET' && p) || o.xmlData){
11188 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11191 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11192 return this.transId;
11194 Roo.callback(o.callback, o.scope, [o, null, null]);
11200 * Determine whether this object has a request outstanding.
11201 * @param {Number} transactionId (Optional) defaults to the last transaction
11202 * @return {Boolean} True if there is an outstanding request.
11204 isLoading : function(transId){
11206 return Roo.lib.Ajax.isCallInProgress(transId);
11208 return this.transId ? true : false;
11213 * Aborts any outstanding request.
11214 * @param {Number} transactionId (Optional) defaults to the last transaction
11216 abort : function(transId){
11217 if(transId || this.isLoading()){
11218 Roo.lib.Ajax.abort(transId || this.transId);
11223 handleResponse : function(response){
11224 this.transId = false;
11225 var options = response.argument.options;
11226 response.argument = options ? options.argument : null;
11227 this.fireEvent("requestcomplete", this, response, options);
11228 Roo.callback(options.success, options.scope, [response, options]);
11229 Roo.callback(options.callback, options.scope, [options, true, response]);
11233 handleFailure : function(response, e){
11234 this.transId = false;
11235 var options = response.argument.options;
11236 response.argument = options ? options.argument : null;
11237 this.fireEvent("requestexception", this, response, options, e);
11238 Roo.callback(options.failure, options.scope, [response, options]);
11239 Roo.callback(options.callback, options.scope, [options, false, response]);
11243 doFormUpload : function(o, ps, url){
11245 var frame = document.createElement('iframe');
11248 frame.className = 'x-hidden';
11250 frame.src = Roo.SSL_SECURE_URL;
11252 document.body.appendChild(frame);
11255 document.frames[id].name = id;
11258 var form = Roo.getDom(o.form);
11260 form.method = 'POST';
11261 form.enctype = form.encoding = 'multipart/form-data';
11267 if(ps){ // add dynamic params
11269 ps = Roo.urlDecode(ps, false);
11271 if(ps.hasOwnProperty(k)){
11272 hd = document.createElement('input');
11273 hd.type = 'hidden';
11276 form.appendChild(hd);
11283 var r = { // bogus response object
11288 r.argument = o ? o.argument : null;
11293 doc = frame.contentWindow.document;
11295 doc = (frame.contentDocument || window.frames[id].document);
11297 if(doc && doc.body){
11298 r.responseText = doc.body.innerHTML;
11300 if(doc && doc.XMLDocument){
11301 r.responseXML = doc.XMLDocument;
11303 r.responseXML = doc;
11310 Roo.EventManager.removeListener(frame, 'load', cb, this);
11312 this.fireEvent("requestcomplete", this, r, o);
11313 Roo.callback(o.success, o.scope, [r, o]);
11314 Roo.callback(o.callback, o.scope, [o, true, r]);
11316 setTimeout(function(){document.body.removeChild(frame);}, 100);
11319 Roo.EventManager.on(frame, 'load', cb, this);
11322 if(hiddens){ // remove dynamic params
11323 for(var i = 0, len = hiddens.length; i < len; i++){
11324 form.removeChild(hiddens[i]);
11332 * @extends Roo.data.Connection
11333 * Global Ajax request class.
11337 Roo.Ajax = new Roo.data.Connection({
11340 * @cfg {String} url @hide
11343 * @cfg {Object} extraParams @hide
11346 * @cfg {Object} defaultHeaders @hide
11349 * @cfg {String} method (Optional) @hide
11352 * @cfg {Number} timeout (Optional) @hide
11355 * @cfg {Boolean} autoAbort (Optional) @hide
11359 * @cfg {Boolean} disableCaching (Optional) @hide
11363 * @property disableCaching
11364 * True to add a unique cache-buster param to GET requests. (defaults to true)
11369 * The default URL to be used for requests to the server. (defaults to undefined)
11373 * @property extraParams
11374 * An object containing properties which are used as
11375 * extra parameters to each request made by this object. (defaults to undefined)
11379 * @property defaultHeaders
11380 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11385 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11389 * @property timeout
11390 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11395 * @property autoAbort
11396 * Whether a new request should abort any pending requests. (defaults to false)
11402 * Serialize the passed form into a url encoded string
11403 * @param {String/HTMLElement} form
11406 serializeForm : function(form){
11407 return Roo.lib.Ajax.serializeForm(form);
11411 * Ext JS Library 1.1.1
11412 * Copyright(c) 2006-2007, Ext JS, LLC.
11414 * Originally Released Under LGPL - original licence link has changed is not relivant.
11417 * <script type="text/javascript">
11422 * @extends Roo.data.Connection
11423 * Global Ajax request class.
11425 * @instanceOf Roo.data.Connection
11427 Roo.Ajax = new Roo.data.Connection({
11436 * @cfg {String} url @hide
11439 * @cfg {Object} extraParams @hide
11442 * @cfg {Object} defaultHeaders @hide
11445 * @cfg {String} method (Optional) @hide
11448 * @cfg {Number} timeout (Optional) @hide
11451 * @cfg {Boolean} autoAbort (Optional) @hide
11455 * @cfg {Boolean} disableCaching (Optional) @hide
11459 * @property disableCaching
11460 * True to add a unique cache-buster param to GET requests. (defaults to true)
11465 * The default URL to be used for requests to the server. (defaults to undefined)
11469 * @property extraParams
11470 * An object containing properties which are used as
11471 * extra parameters to each request made by this object. (defaults to undefined)
11475 * @property defaultHeaders
11476 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11481 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11485 * @property timeout
11486 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11491 * @property autoAbort
11492 * Whether a new request should abort any pending requests. (defaults to false)
11498 * Serialize the passed form into a url encoded string
11499 * @param {String/HTMLElement} form
11502 serializeForm : function(form){
11503 return Roo.lib.Ajax.serializeForm(form);
11507 * Ext JS Library 1.1.1
11508 * Copyright(c) 2006-2007, Ext JS, LLC.
11510 * Originally Released Under LGPL - original licence link has changed is not relivant.
11513 * <script type="text/javascript">
11518 * @class Roo.UpdateManager
11519 * @extends Roo.util.Observable
11520 * Provides AJAX-style update for Element object.<br><br>
11523 * // Get it from a Roo.Element object
11524 * var el = Roo.get("foo");
11525 * var mgr = el.getUpdateManager();
11526 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11528 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11530 * // or directly (returns the same UpdateManager instance)
11531 * var mgr = new Roo.UpdateManager("myElementId");
11532 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11533 * mgr.on("update", myFcnNeedsToKnow);
11535 // short handed call directly from the element object
11536 Roo.get("foo").load({
11540 text: "Loading Foo..."
11544 * Create new UpdateManager directly.
11545 * @param {String/HTMLElement/Roo.Element} el The element to update
11546 * @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).
11548 Roo.UpdateManager = function(el, forceNew){
11550 if(!forceNew && el.updateManager){
11551 return el.updateManager;
11554 * The Element object
11555 * @type Roo.Element
11559 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11562 this.defaultUrl = null;
11566 * @event beforeupdate
11567 * Fired before an update is made, return false from your handler and the update is cancelled.
11568 * @param {Roo.Element} el
11569 * @param {String/Object/Function} url
11570 * @param {String/Object} params
11572 "beforeupdate": true,
11575 * Fired after successful update is made.
11576 * @param {Roo.Element} el
11577 * @param {Object} oResponseObject The response Object
11582 * Fired on update failure.
11583 * @param {Roo.Element} el
11584 * @param {Object} oResponseObject The response Object
11588 var d = Roo.UpdateManager.defaults;
11590 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11593 this.sslBlankUrl = d.sslBlankUrl;
11595 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11598 this.disableCaching = d.disableCaching;
11600 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11603 this.indicatorText = d.indicatorText;
11605 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11608 this.showLoadIndicator = d.showLoadIndicator;
11610 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11613 this.timeout = d.timeout;
11616 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11619 this.loadScripts = d.loadScripts;
11622 * Transaction object of current executing transaction
11624 this.transaction = null;
11629 this.autoRefreshProcId = null;
11631 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11634 this.refreshDelegate = this.refresh.createDelegate(this);
11636 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11639 this.updateDelegate = this.update.createDelegate(this);
11641 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11644 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11648 this.successDelegate = this.processSuccess.createDelegate(this);
11652 this.failureDelegate = this.processFailure.createDelegate(this);
11654 if(!this.renderer){
11656 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11658 this.renderer = new Roo.UpdateManager.BasicRenderer();
11661 Roo.UpdateManager.superclass.constructor.call(this);
11664 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11666 * Get the Element this UpdateManager is bound to
11667 * @return {Roo.Element} The element
11669 getEl : function(){
11673 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11674 * @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:
11677 url: "your-url.php",<br/>
11678 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11679 callback: yourFunction,<br/>
11680 scope: yourObject, //(optional scope) <br/>
11681 discardUrl: false, <br/>
11682 nocache: false,<br/>
11683 text: "Loading...",<br/>
11685 scripts: false<br/>
11688 * The only required property is url. The optional properties nocache, text and scripts
11689 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11690 * @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}
11691 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11692 * @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.
11694 update : function(url, params, callback, discardUrl){
11695 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11696 var method = this.method, cfg;
11697 if(typeof url == "object"){ // must be config object
11700 params = params || cfg.params;
11701 callback = callback || cfg.callback;
11702 discardUrl = discardUrl || cfg.discardUrl;
11703 if(callback && cfg.scope){
11704 callback = callback.createDelegate(cfg.scope);
11706 if(typeof cfg.method != "undefined"){method = cfg.method;};
11707 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11708 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11709 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11710 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11712 this.showLoading();
11714 this.defaultUrl = url;
11716 if(typeof url == "function"){
11717 url = url.call(this);
11720 method = method || (params ? "POST" : "GET");
11721 if(method == "GET"){
11722 url = this.prepareUrl(url);
11725 var o = Roo.apply(cfg ||{}, {
11728 success: this.successDelegate,
11729 failure: this.failureDelegate,
11730 callback: undefined,
11731 timeout: (this.timeout*1000),
11732 argument: {"url": url, "form": null, "callback": callback, "params": params}
11735 this.transaction = Roo.Ajax.request(o);
11740 * 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.
11741 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11742 * @param {String/HTMLElement} form The form Id or form element
11743 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11744 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11745 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11747 formUpdate : function(form, url, reset, callback){
11748 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11749 if(typeof url == "function"){
11750 url = url.call(this);
11752 form = Roo.getDom(form);
11753 this.transaction = Roo.Ajax.request({
11756 success: this.successDelegate,
11757 failure: this.failureDelegate,
11758 timeout: (this.timeout*1000),
11759 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11761 this.showLoading.defer(1, this);
11766 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11767 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11769 refresh : function(callback){
11770 if(this.defaultUrl == null){
11773 this.update(this.defaultUrl, null, callback, true);
11777 * Set this element to auto refresh.
11778 * @param {Number} interval How often to update (in seconds).
11779 * @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)
11780 * @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}
11781 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11782 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11784 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11786 this.update(url || this.defaultUrl, params, callback, true);
11788 if(this.autoRefreshProcId){
11789 clearInterval(this.autoRefreshProcId);
11791 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11795 * Stop auto refresh on this element.
11797 stopAutoRefresh : function(){
11798 if(this.autoRefreshProcId){
11799 clearInterval(this.autoRefreshProcId);
11800 delete this.autoRefreshProcId;
11804 isAutoRefreshing : function(){
11805 return this.autoRefreshProcId ? true : false;
11808 * Called to update the element to "Loading" state. Override to perform custom action.
11810 showLoading : function(){
11811 if(this.showLoadIndicator){
11812 this.el.update(this.indicatorText);
11817 * Adds unique parameter to query string if disableCaching = true
11820 prepareUrl : function(url){
11821 if(this.disableCaching){
11822 var append = "_dc=" + (new Date().getTime());
11823 if(url.indexOf("?") !== -1){
11824 url += "&" + append;
11826 url += "?" + append;
11835 processSuccess : function(response){
11836 this.transaction = null;
11837 if(response.argument.form && response.argument.reset){
11838 try{ // put in try/catch since some older FF releases had problems with this
11839 response.argument.form.reset();
11842 if(this.loadScripts){
11843 this.renderer.render(this.el, response, this,
11844 this.updateComplete.createDelegate(this, [response]));
11846 this.renderer.render(this.el, response, this);
11847 this.updateComplete(response);
11851 updateComplete : function(response){
11852 this.fireEvent("update", this.el, response);
11853 if(typeof response.argument.callback == "function"){
11854 response.argument.callback(this.el, true, response);
11861 processFailure : function(response){
11862 this.transaction = null;
11863 this.fireEvent("failure", this.el, response);
11864 if(typeof response.argument.callback == "function"){
11865 response.argument.callback(this.el, false, response);
11870 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11871 * @param {Object} renderer The object implementing the render() method
11873 setRenderer : function(renderer){
11874 this.renderer = renderer;
11877 getRenderer : function(){
11878 return this.renderer;
11882 * Set the defaultUrl used for updates
11883 * @param {String/Function} defaultUrl The url or a function to call to get the url
11885 setDefaultUrl : function(defaultUrl){
11886 this.defaultUrl = defaultUrl;
11890 * Aborts the executing transaction
11892 abort : function(){
11893 if(this.transaction){
11894 Roo.Ajax.abort(this.transaction);
11899 * Returns true if an update is in progress
11900 * @return {Boolean}
11902 isUpdating : function(){
11903 if(this.transaction){
11904 return Roo.Ajax.isLoading(this.transaction);
11911 * @class Roo.UpdateManager.defaults
11912 * @static (not really - but it helps the doc tool)
11913 * The defaults collection enables customizing the default properties of UpdateManager
11915 Roo.UpdateManager.defaults = {
11917 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11923 * True to process scripts by default (Defaults to false).
11926 loadScripts : false,
11929 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11932 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11934 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11937 disableCaching : false,
11939 * Whether to show indicatorText when loading (Defaults to true).
11942 showLoadIndicator : true,
11944 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11947 indicatorText : '<div class="loading-indicator">Loading...</div>'
11951 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11953 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11954 * @param {String/HTMLElement/Roo.Element} el The element to update
11955 * @param {String} url The url
11956 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11957 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11960 * @member Roo.UpdateManager
11962 Roo.UpdateManager.updateElement = function(el, url, params, options){
11963 var um = Roo.get(el, true).getUpdateManager();
11964 Roo.apply(um, options);
11965 um.update(url, params, options ? options.callback : null);
11967 // alias for backwards compat
11968 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11970 * @class Roo.UpdateManager.BasicRenderer
11971 * Default Content renderer. Updates the elements innerHTML with the responseText.
11973 Roo.UpdateManager.BasicRenderer = function(){};
11975 Roo.UpdateManager.BasicRenderer.prototype = {
11977 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11978 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11979 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11980 * @param {Roo.Element} el The element being rendered
11981 * @param {Object} response The YUI Connect response object
11982 * @param {UpdateManager} updateManager The calling update manager
11983 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11985 render : function(el, response, updateManager, callback){
11986 el.update(response.responseText, updateManager.loadScripts, callback);
11991 * Ext JS Library 1.1.1
11992 * Copyright(c) 2006-2007, Ext JS, LLC.
11994 * Originally Released Under LGPL - original licence link has changed is not relivant.
11997 * <script type="text/javascript">
12001 * @class Roo.util.DelayedTask
12002 * Provides a convenient method of performing setTimeout where a new
12003 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12004 * You can use this class to buffer
12005 * the keypress events for a certain number of milliseconds, and perform only if they stop
12006 * for that amount of time.
12007 * @constructor The parameters to this constructor serve as defaults and are not required.
12008 * @param {Function} fn (optional) The default function to timeout
12009 * @param {Object} scope (optional) The default scope of that timeout
12010 * @param {Array} args (optional) The default Array of arguments
12012 Roo.util.DelayedTask = function(fn, scope, args){
12013 var id = null, d, t;
12015 var call = function(){
12016 var now = new Date().getTime();
12020 fn.apply(scope, args || []);
12024 * Cancels any pending timeout and queues a new one
12025 * @param {Number} delay The milliseconds to delay
12026 * @param {Function} newFn (optional) Overrides function passed to constructor
12027 * @param {Object} newScope (optional) Overrides scope passed to constructor
12028 * @param {Array} newArgs (optional) Overrides args passed to constructor
12030 this.delay = function(delay, newFn, newScope, newArgs){
12031 if(id && delay != d){
12035 t = new Date().getTime();
12037 scope = newScope || scope;
12038 args = newArgs || args;
12040 id = setInterval(call, d);
12045 * Cancel the last queued timeout
12047 this.cancel = function(){
12055 * Ext JS Library 1.1.1
12056 * Copyright(c) 2006-2007, Ext JS, LLC.
12058 * Originally Released Under LGPL - original licence link has changed is not relivant.
12061 * <script type="text/javascript">
12065 Roo.util.TaskRunner = function(interval){
12066 interval = interval || 10;
12067 var tasks = [], removeQueue = [];
12069 var running = false;
12071 var stopThread = function(){
12077 var startThread = function(){
12080 id = setInterval(runTasks, interval);
12084 var removeTask = function(task){
12085 removeQueue.push(task);
12091 var runTasks = function(){
12092 if(removeQueue.length > 0){
12093 for(var i = 0, len = removeQueue.length; i < len; i++){
12094 tasks.remove(removeQueue[i]);
12097 if(tasks.length < 1){
12102 var now = new Date().getTime();
12103 for(var i = 0, len = tasks.length; i < len; ++i){
12105 var itime = now - t.taskRunTime;
12106 if(t.interval <= itime){
12107 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12108 t.taskRunTime = now;
12109 if(rt === false || t.taskRunCount === t.repeat){
12114 if(t.duration && t.duration <= (now - t.taskStartTime)){
12121 * Queues a new task.
12122 * @param {Object} task
12124 this.start = function(task){
12126 task.taskStartTime = new Date().getTime();
12127 task.taskRunTime = 0;
12128 task.taskRunCount = 0;
12133 this.stop = function(task){
12138 this.stopAll = function(){
12140 for(var i = 0, len = tasks.length; i < len; i++){
12141 if(tasks[i].onStop){
12150 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12152 * Ext JS Library 1.1.1
12153 * Copyright(c) 2006-2007, Ext JS, LLC.
12155 * Originally Released Under LGPL - original licence link has changed is not relivant.
12158 * <script type="text/javascript">
12163 * @class Roo.util.MixedCollection
12164 * @extends Roo.util.Observable
12165 * A Collection class that maintains both numeric indexes and keys and exposes events.
12167 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12168 * collection (defaults to false)
12169 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12170 * and return the key value for that item. This is used when available to look up the key on items that
12171 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12172 * equivalent to providing an implementation for the {@link #getKey} method.
12174 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12182 * Fires when the collection is cleared.
12187 * Fires when an item is added to the collection.
12188 * @param {Number} index The index at which the item was added.
12189 * @param {Object} o The item added.
12190 * @param {String} key The key associated with the added item.
12195 * Fires when an item is replaced in the collection.
12196 * @param {String} key he key associated with the new added.
12197 * @param {Object} old The item being replaced.
12198 * @param {Object} new The new item.
12203 * Fires when an item is removed from the collection.
12204 * @param {Object} o The item being removed.
12205 * @param {String} key (optional) The key associated with the removed item.
12210 this.allowFunctions = allowFunctions === true;
12212 this.getKey = keyFn;
12214 Roo.util.MixedCollection.superclass.constructor.call(this);
12217 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12218 allowFunctions : false,
12221 * Adds an item to the collection.
12222 * @param {String} key The key to associate with the item
12223 * @param {Object} o The item to add.
12224 * @return {Object} The item added.
12226 add : function(key, o){
12227 if(arguments.length == 1){
12229 key = this.getKey(o);
12231 if(typeof key == "undefined" || key === null){
12233 this.items.push(o);
12234 this.keys.push(null);
12236 var old = this.map[key];
12238 return this.replace(key, o);
12241 this.items.push(o);
12243 this.keys.push(key);
12245 this.fireEvent("add", this.length-1, o, key);
12250 * MixedCollection has a generic way to fetch keys if you implement getKey.
12253 var mc = new Roo.util.MixedCollection();
12254 mc.add(someEl.dom.id, someEl);
12255 mc.add(otherEl.dom.id, otherEl);
12259 var mc = new Roo.util.MixedCollection();
12260 mc.getKey = function(el){
12266 // or via the constructor
12267 var mc = new Roo.util.MixedCollection(false, function(el){
12273 * @param o {Object} The item for which to find the key.
12274 * @return {Object} The key for the passed item.
12276 getKey : function(o){
12281 * Replaces an item in the collection.
12282 * @param {String} key The key associated with the item to replace, or the item to replace.
12283 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12284 * @return {Object} The new item.
12286 replace : function(key, o){
12287 if(arguments.length == 1){
12289 key = this.getKey(o);
12291 var old = this.item(key);
12292 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12293 return this.add(key, o);
12295 var index = this.indexOfKey(key);
12296 this.items[index] = o;
12298 this.fireEvent("replace", key, old, o);
12303 * Adds all elements of an Array or an Object to the collection.
12304 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12305 * an Array of values, each of which are added to the collection.
12307 addAll : function(objs){
12308 if(arguments.length > 1 || objs instanceof Array){
12309 var args = arguments.length > 1 ? arguments : objs;
12310 for(var i = 0, len = args.length; i < len; i++){
12314 for(var key in objs){
12315 if(this.allowFunctions || typeof objs[key] != "function"){
12316 this.add(key, objs[key]);
12323 * Executes the specified function once for every item in the collection, passing each
12324 * item as the first and only parameter. returning false from the function will stop the iteration.
12325 * @param {Function} fn The function to execute for each item.
12326 * @param {Object} scope (optional) The scope in which to execute the function.
12328 each : function(fn, scope){
12329 var items = [].concat(this.items); // each safe for removal
12330 for(var i = 0, len = items.length; i < len; i++){
12331 if(fn.call(scope || items[i], items[i], i, len) === false){
12338 * Executes the specified function once for every key in the collection, passing each
12339 * key, and its associated item as the first two parameters.
12340 * @param {Function} fn The function to execute for each item.
12341 * @param {Object} scope (optional) The scope in which to execute the function.
12343 eachKey : function(fn, scope){
12344 for(var i = 0, len = this.keys.length; i < len; i++){
12345 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12350 * Returns the first item in the collection which elicits a true return value from the
12351 * passed selection function.
12352 * @param {Function} fn The selection function to execute for each item.
12353 * @param {Object} scope (optional) The scope in which to execute the function.
12354 * @return {Object} The first item in the collection which returned true from the selection function.
12356 find : function(fn, scope){
12357 for(var i = 0, len = this.items.length; i < len; i++){
12358 if(fn.call(scope || window, this.items[i], this.keys[i])){
12359 return this.items[i];
12366 * Inserts an item at the specified index in the collection.
12367 * @param {Number} index The index to insert the item at.
12368 * @param {String} key The key to associate with the new item, or the item itself.
12369 * @param {Object} o (optional) If the second parameter was a key, the new item.
12370 * @return {Object} The item inserted.
12372 insert : function(index, key, o){
12373 if(arguments.length == 2){
12375 key = this.getKey(o);
12377 if(index >= this.length){
12378 return this.add(key, o);
12381 this.items.splice(index, 0, o);
12382 if(typeof key != "undefined" && key != null){
12385 this.keys.splice(index, 0, key);
12386 this.fireEvent("add", index, o, key);
12391 * Removed an item from the collection.
12392 * @param {Object} o The item to remove.
12393 * @return {Object} The item removed.
12395 remove : function(o){
12396 return this.removeAt(this.indexOf(o));
12400 * Remove an item from a specified index in the collection.
12401 * @param {Number} index The index within the collection of the item to remove.
12403 removeAt : function(index){
12404 if(index < this.length && index >= 0){
12406 var o = this.items[index];
12407 this.items.splice(index, 1);
12408 var key = this.keys[index];
12409 if(typeof key != "undefined"){
12410 delete this.map[key];
12412 this.keys.splice(index, 1);
12413 this.fireEvent("remove", o, key);
12418 * Removed an item associated with the passed key fom the collection.
12419 * @param {String} key The key of the item to remove.
12421 removeKey : function(key){
12422 return this.removeAt(this.indexOfKey(key));
12426 * Returns the number of items in the collection.
12427 * @return {Number} the number of items in the collection.
12429 getCount : function(){
12430 return this.length;
12434 * Returns index within the collection of the passed Object.
12435 * @param {Object} o The item to find the index of.
12436 * @return {Number} index of the item.
12438 indexOf : function(o){
12439 if(!this.items.indexOf){
12440 for(var i = 0, len = this.items.length; i < len; i++){
12441 if(this.items[i] == o) return i;
12445 return this.items.indexOf(o);
12450 * Returns index within the collection of the passed key.
12451 * @param {String} key The key to find the index of.
12452 * @return {Number} index of the key.
12454 indexOfKey : function(key){
12455 if(!this.keys.indexOf){
12456 for(var i = 0, len = this.keys.length; i < len; i++){
12457 if(this.keys[i] == key) return i;
12461 return this.keys.indexOf(key);
12466 * Returns the item associated with the passed key OR index. Key has priority over index.
12467 * @param {String/Number} key The key or index of the item.
12468 * @return {Object} The item associated with the passed key.
12470 item : function(key){
12471 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12472 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12476 * Returns the item at the specified index.
12477 * @param {Number} index The index of the item.
12480 itemAt : function(index){
12481 return this.items[index];
12485 * Returns the item associated with the passed key.
12486 * @param {String/Number} key The key of the item.
12487 * @return {Object} The item associated with the passed key.
12489 key : function(key){
12490 return this.map[key];
12494 * Returns true if the collection contains the passed Object as an item.
12495 * @param {Object} o The Object to look for in the collection.
12496 * @return {Boolean} True if the collection contains the Object as an item.
12498 contains : function(o){
12499 return this.indexOf(o) != -1;
12503 * Returns true if the collection contains the passed Object as a key.
12504 * @param {String} key The key to look for in the collection.
12505 * @return {Boolean} True if the collection contains the Object as a key.
12507 containsKey : function(key){
12508 return typeof this.map[key] != "undefined";
12512 * Removes all items from the collection.
12514 clear : function(){
12519 this.fireEvent("clear");
12523 * Returns the first item in the collection.
12524 * @return {Object} the first item in the collection..
12526 first : function(){
12527 return this.items[0];
12531 * Returns the last item in the collection.
12532 * @return {Object} the last item in the collection..
12535 return this.items[this.length-1];
12538 _sort : function(property, dir, fn){
12539 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12540 fn = fn || function(a, b){
12543 var c = [], k = this.keys, items = this.items;
12544 for(var i = 0, len = items.length; i < len; i++){
12545 c[c.length] = {key: k[i], value: items[i], index: i};
12547 c.sort(function(a, b){
12548 var v = fn(a[property], b[property]) * dsc;
12550 v = (a.index < b.index ? -1 : 1);
12554 for(var i = 0, len = c.length; i < len; i++){
12555 items[i] = c[i].value;
12558 this.fireEvent("sort", this);
12562 * Sorts this collection with the passed comparison function
12563 * @param {String} direction (optional) "ASC" or "DESC"
12564 * @param {Function} fn (optional) comparison function
12566 sort : function(dir, fn){
12567 this._sort("value", dir, fn);
12571 * Sorts this collection by keys
12572 * @param {String} direction (optional) "ASC" or "DESC"
12573 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12575 keySort : function(dir, fn){
12576 this._sort("key", dir, fn || function(a, b){
12577 return String(a).toUpperCase()-String(b).toUpperCase();
12582 * Returns a range of items in this collection
12583 * @param {Number} startIndex (optional) defaults to 0
12584 * @param {Number} endIndex (optional) default to the last item
12585 * @return {Array} An array of items
12587 getRange : function(start, end){
12588 var items = this.items;
12589 if(items.length < 1){
12592 start = start || 0;
12593 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12596 for(var i = start; i <= end; i++) {
12597 r[r.length] = items[i];
12600 for(var i = start; i >= end; i--) {
12601 r[r.length] = items[i];
12608 * Filter the <i>objects</i> in this collection by a specific property.
12609 * Returns a new collection that has been filtered.
12610 * @param {String} property A property on your objects
12611 * @param {String/RegExp} value Either string that the property values
12612 * should start with or a RegExp to test against the property
12613 * @return {MixedCollection} The new filtered collection
12615 filter : function(property, value){
12616 if(!value.exec){ // not a regex
12617 value = String(value);
12618 if(value.length == 0){
12619 return this.clone();
12621 value = new RegExp("^" + Roo.escapeRe(value), "i");
12623 return this.filterBy(function(o){
12624 return o && value.test(o[property]);
12629 * Filter by a function. * Returns a new collection that has been filtered.
12630 * The passed function will be called with each
12631 * object in the collection. If the function returns true, the value is included
12632 * otherwise it is filtered.
12633 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12634 * @param {Object} scope (optional) The scope of the function (defaults to this)
12635 * @return {MixedCollection} The new filtered collection
12637 filterBy : function(fn, scope){
12638 var r = new Roo.util.MixedCollection();
12639 r.getKey = this.getKey;
12640 var k = this.keys, it = this.items;
12641 for(var i = 0, len = it.length; i < len; i++){
12642 if(fn.call(scope||this, it[i], k[i])){
12643 r.add(k[i], it[i]);
12650 * Creates a duplicate of this collection
12651 * @return {MixedCollection}
12653 clone : function(){
12654 var r = new Roo.util.MixedCollection();
12655 var k = this.keys, it = this.items;
12656 for(var i = 0, len = it.length; i < len; i++){
12657 r.add(k[i], it[i]);
12659 r.getKey = this.getKey;
12664 * Returns the item associated with the passed key or index.
12666 * @param {String/Number} key The key or index of the item.
12667 * @return {Object} The item associated with the passed key.
12669 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12671 * Ext JS Library 1.1.1
12672 * Copyright(c) 2006-2007, Ext JS, LLC.
12674 * Originally Released Under LGPL - original licence link has changed is not relivant.
12677 * <script type="text/javascript">
12680 * @class Roo.util.JSON
12681 * Modified version of Douglas Crockford"s json.js that doesn"t
12682 * mess with the Object prototype
12683 * http://www.json.org/js.html
12686 Roo.util.JSON = new (function(){
12687 var useHasOwn = {}.hasOwnProperty ? true : false;
12689 // crashes Safari in some instances
12690 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12692 var pad = function(n) {
12693 return n < 10 ? "0" + n : n;
12706 var encodeString = function(s){
12707 if (/["\\\x00-\x1f]/.test(s)) {
12708 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12713 c = b.charCodeAt();
12715 Math.floor(c / 16).toString(16) +
12716 (c % 16).toString(16);
12719 return '"' + s + '"';
12722 var encodeArray = function(o){
12723 var a = ["["], b, i, l = o.length, v;
12724 for (i = 0; i < l; i += 1) {
12726 switch (typeof v) {
12735 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12743 var encodeDate = function(o){
12744 return '"' + o.getFullYear() + "-" +
12745 pad(o.getMonth() + 1) + "-" +
12746 pad(o.getDate()) + "T" +
12747 pad(o.getHours()) + ":" +
12748 pad(o.getMinutes()) + ":" +
12749 pad(o.getSeconds()) + '"';
12753 * Encodes an Object, Array or other value
12754 * @param {Mixed} o The variable to encode
12755 * @return {String} The JSON string
12757 this.encode = function(o){
12758 if(typeof o == "undefined" || o === null){
12760 }else if(o instanceof Array){
12761 return encodeArray(o);
12762 }else if(o instanceof Date){
12763 return encodeDate(o);
12764 }else if(typeof o == "string"){
12765 return encodeString(o);
12766 }else if(typeof o == "number"){
12767 return isFinite(o) ? String(o) : "null";
12768 }else if(typeof o == "boolean"){
12771 var a = ["{"], b, i, v;
12773 if(!useHasOwn || o.hasOwnProperty(i)) {
12775 switch (typeof v) {
12784 a.push(this.encode(i), ":",
12785 v === null ? "null" : this.encode(v));
12796 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12797 * @param {String} json The JSON string
12798 * @return {Object} The resulting object
12800 this.decode = function(json){
12804 return eval("(" + json + ')');
12808 * Shorthand for {@link Roo.util.JSON#encode}
12809 * @member Roo encode
12811 Roo.encode = Roo.util.JSON.encode;
12813 * Shorthand for {@link Roo.util.JSON#decode}
12814 * @member Roo decode
12816 Roo.decode = Roo.util.JSON.decode;
12819 * Ext JS Library 1.1.1
12820 * Copyright(c) 2006-2007, Ext JS, LLC.
12822 * Originally Released Under LGPL - original licence link has changed is not relivant.
12825 * <script type="text/javascript">
12829 * @class Roo.util.Format
12830 * Reusable data formatting functions
12833 Roo.util.Format = function(){
12834 var trimRe = /^\s+|\s+$/g;
12837 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12838 * @param {String} value The string to truncate
12839 * @param {Number} length The maximum length to allow before truncating
12840 * @return {String} The converted text
12842 ellipsis : function(value, len){
12843 if(value && value.length > len){
12844 return value.substr(0, len-3)+"...";
12850 * Checks a reference and converts it to empty string if it is undefined
12851 * @param {Mixed} value Reference to check
12852 * @return {Mixed} Empty string if converted, otherwise the original value
12854 undef : function(value){
12855 return typeof value != "undefined" ? value : "";
12859 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12860 * @param {String} value The string to encode
12861 * @return {String} The encoded text
12863 htmlEncode : function(value){
12864 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12868 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12869 * @param {String} value The string to decode
12870 * @return {String} The decoded text
12872 htmlDecode : function(value){
12873 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12877 * Trims any whitespace from either side of a string
12878 * @param {String} value The text to trim
12879 * @return {String} The trimmed text
12881 trim : function(value){
12882 return String(value).replace(trimRe, "");
12886 * Returns a substring from within an original string
12887 * @param {String} value The original text
12888 * @param {Number} start The start index of the substring
12889 * @param {Number} length The length of the substring
12890 * @return {String} The substring
12892 substr : function(value, start, length){
12893 return String(value).substr(start, length);
12897 * Converts a string to all lower case letters
12898 * @param {String} value The text to convert
12899 * @return {String} The converted text
12901 lowercase : function(value){
12902 return String(value).toLowerCase();
12906 * Converts a string to all upper case letters
12907 * @param {String} value The text to convert
12908 * @return {String} The converted text
12910 uppercase : function(value){
12911 return String(value).toUpperCase();
12915 * Converts the first character only of a string to upper case
12916 * @param {String} value The text to convert
12917 * @return {String} The converted text
12919 capitalize : function(value){
12920 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12924 call : function(value, fn){
12925 if(arguments.length > 2){
12926 var args = Array.prototype.slice.call(arguments, 2);
12927 args.unshift(value);
12929 return /** eval:var:value */ eval(fn).apply(window, args);
12931 /** eval:var:value */
12932 return /** eval:var:value */ eval(fn).call(window, value);
12937 * Format a number as US currency
12938 * @param {Number/String} value The numeric value to format
12939 * @return {String} The formatted currency string
12941 usMoney : function(v){
12942 v = (Math.round((v-0)*100))/100;
12943 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12945 var ps = v.split('.');
12947 var sub = ps[1] ? '.'+ ps[1] : '.00';
12948 var r = /(\d+)(\d{3})/;
12949 while (r.test(whole)) {
12950 whole = whole.replace(r, '$1' + ',' + '$2');
12952 return "$" + whole + sub ;
12956 * Parse a value into a formatted date using the specified format pattern.
12957 * @param {Mixed} value The value to format
12958 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12959 * @return {String} The formatted date string
12961 date : function(v, format){
12965 if(!(v instanceof Date)){
12966 v = new Date(Date.parse(v));
12968 return v.dateFormat(format || "m/d/Y");
12972 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12973 * @param {String} format Any valid date format string
12974 * @return {Function} The date formatting function
12976 dateRenderer : function(format){
12977 return function(v){
12978 return Roo.util.Format.date(v, format);
12983 stripTagsRE : /<\/?[^>]+>/gi,
12986 * Strips all HTML tags
12987 * @param {Mixed} value The text from which to strip tags
12988 * @return {String} The stripped text
12990 stripTags : function(v){
12991 return !v ? v : String(v).replace(this.stripTagsRE, "");
12996 * Ext JS Library 1.1.1
12997 * Copyright(c) 2006-2007, Ext JS, LLC.
12999 * Originally Released Under LGPL - original licence link has changed is not relivant.
13002 * <script type="text/javascript">
13009 * @class Roo.MasterTemplate
13010 * @extends Roo.Template
13011 * Provides a template that can have child templates. The syntax is:
13013 var t = new Roo.MasterTemplate(
13014 '<select name="{name}">',
13015 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13018 t.add('options', {value: 'foo', text: 'bar'});
13019 // or you can add multiple child elements in one shot
13020 t.addAll('options', [
13021 {value: 'foo', text: 'bar'},
13022 {value: 'foo2', text: 'bar2'},
13023 {value: 'foo3', text: 'bar3'}
13025 // then append, applying the master template values
13026 t.append('my-form', {name: 'my-select'});
13028 * A name attribute for the child template is not required if you have only one child
13029 * template or you want to refer to them by index.
13031 Roo.MasterTemplate = function(){
13032 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13033 this.originalHtml = this.html;
13035 var m, re = this.subTemplateRe;
13038 while(m = re.exec(this.html)){
13039 var name = m[1], content = m[2];
13044 tpl : new Roo.Template(content)
13047 st[name] = st[subIndex];
13049 st[subIndex].tpl.compile();
13050 st[subIndex].tpl.call = this.call.createDelegate(this);
13053 this.subCount = subIndex;
13056 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13058 * The regular expression used to match sub templates
13062 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13065 * Applies the passed values to a child template.
13066 * @param {String/Number} name (optional) The name or index of the child template
13067 * @param {Array/Object} values The values to be applied to the template
13068 * @return {MasterTemplate} this
13070 add : function(name, values){
13071 if(arguments.length == 1){
13072 values = arguments[0];
13075 var s = this.subs[name];
13076 s.buffer[s.buffer.length] = s.tpl.apply(values);
13081 * Applies all the passed values to a child template.
13082 * @param {String/Number} name (optional) The name or index of the child template
13083 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13084 * @param {Boolean} reset (optional) True to reset the template first
13085 * @return {MasterTemplate} this
13087 fill : function(name, values, reset){
13089 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13097 for(var i = 0, len = values.length; i < len; i++){
13098 this.add(name, values[i]);
13104 * Resets the template for reuse
13105 * @return {MasterTemplate} this
13107 reset : function(){
13109 for(var i = 0; i < this.subCount; i++){
13115 applyTemplate : function(values){
13117 var replaceIndex = -1;
13118 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13119 return s[++replaceIndex].buffer.join("");
13121 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13124 apply : function(){
13125 return this.applyTemplate.apply(this, arguments);
13128 compile : function(){return this;}
13132 * Alias for fill().
13135 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13137 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13138 * var tpl = Roo.MasterTemplate.from('element-id');
13139 * @param {String/HTMLElement} el
13140 * @param {Object} config
13143 Roo.MasterTemplate.from = function(el, config){
13144 el = Roo.getDom(el);
13145 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13148 * Ext JS Library 1.1.1
13149 * Copyright(c) 2006-2007, Ext JS, LLC.
13151 * Originally Released Under LGPL - original licence link has changed is not relivant.
13154 * <script type="text/javascript">
13159 * @class Roo.util.CSS
13160 * Utility class for manipulating CSS rules
13163 Roo.util.CSS = function(){
13165 var doc = document;
13167 var camelRe = /(-[a-z])/gi;
13168 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13172 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13173 * tag and appended to the HEAD of the document.
13174 * @param {String} cssText The text containing the css rules
13175 * @param {String} id An id to add to the stylesheet for later removal
13176 * @return {StyleSheet}
13178 createStyleSheet : function(cssText, id){
13180 var head = doc.getElementsByTagName("head")[0];
13181 var rules = doc.createElement("style");
13182 rules.setAttribute("type", "text/css");
13184 rules.setAttribute("id", id);
13187 head.appendChild(rules);
13188 ss = rules.styleSheet;
13189 ss.cssText = cssText;
13192 rules.appendChild(doc.createTextNode(cssText));
13194 rules.cssText = cssText;
13196 head.appendChild(rules);
13197 ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13199 this.cacheStyleSheet(ss);
13204 * Removes a style or link tag by id
13205 * @param {String} id The id of the tag
13207 removeStyleSheet : function(id){
13208 var existing = doc.getElementById(id);
13210 existing.parentNode.removeChild(existing);
13215 * Dynamically swaps an existing stylesheet reference for a new one
13216 * @param {String} id The id of an existing link tag to remove
13217 * @param {String} url The href of the new stylesheet to include
13219 swapStyleSheet : function(id, url){
13220 this.removeStyleSheet(id);
13221 var ss = doc.createElement("link");
13222 ss.setAttribute("rel", "stylesheet");
13223 ss.setAttribute("type", "text/css");
13224 ss.setAttribute("id", id);
13225 ss.setAttribute("href", url);
13226 doc.getElementsByTagName("head")[0].appendChild(ss);
13230 * Refresh the rule cache if you have dynamically added stylesheets
13231 * @return {Object} An object (hash) of rules indexed by selector
13233 refreshCache : function(){
13234 return this.getRules(true);
13238 cacheStyleSheet : function(ss){
13242 try{// try catch for cross domain access issue
13243 var ssRules = ss.cssRules || ss.rules;
13244 for(var j = ssRules.length-1; j >= 0; --j){
13245 rules[ssRules[j].selectorText] = ssRules[j];
13251 * Gets all css rules for the document
13252 * @param {Boolean} refreshCache true to refresh the internal cache
13253 * @return {Object} An object (hash) of rules indexed by selector
13255 getRules : function(refreshCache){
13256 if(rules == null || refreshCache){
13258 var ds = doc.styleSheets;
13259 for(var i =0, len = ds.length; i < len; i++){
13261 this.cacheStyleSheet(ds[i]);
13269 * Gets an an individual CSS rule by selector(s)
13270 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13271 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13272 * @return {CSSRule} The CSS rule or null if one is not found
13274 getRule : function(selector, refreshCache){
13275 var rs = this.getRules(refreshCache);
13276 if(!(selector instanceof Array)){
13277 return rs[selector];
13279 for(var i = 0; i < selector.length; i++){
13280 if(rs[selector[i]]){
13281 return rs[selector[i]];
13289 * Updates a rule property
13290 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13291 * @param {String} property The css property
13292 * @param {String} value The new value for the property
13293 * @return {Boolean} true If a rule was found and updated
13295 updateRule : function(selector, property, value){
13296 if(!(selector instanceof Array)){
13297 var rule = this.getRule(selector);
13299 rule.style[property.replace(camelRe, camelFn)] = value;
13303 for(var i = 0; i < selector.length; i++){
13304 if(this.updateRule(selector[i], property, value)){
13314 * Ext JS Library 1.1.1
13315 * Copyright(c) 2006-2007, Ext JS, LLC.
13317 * Originally Released Under LGPL - original licence link has changed is not relivant.
13320 * <script type="text/javascript">
13326 * @class Roo.util.ClickRepeater
13327 * @extends Roo.util.Observable
13329 * A wrapper class which can be applied to any element. Fires a "click" event while the
13330 * mouse is pressed. The interval between firings may be specified in the config but
13331 * defaults to 10 milliseconds.
13333 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13335 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13336 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13337 * Similar to an autorepeat key delay.
13338 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13339 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13340 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13341 * "interval" and "delay" are ignored. "immediate" is honored.
13342 * @cfg {Boolean} preventDefault True to prevent the default click event
13343 * @cfg {Boolean} stopDefault True to stop the default click event
13346 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13347 * 2007-02-02 jvs Renamed to ClickRepeater
13348 * 2007-02-03 jvs Modifications for FF Mac and Safari
13351 * @param {String/HTMLElement/Element} el The element to listen on
13352 * @param {Object} config
13354 Roo.util.ClickRepeater = function(el, config)
13356 this.el = Roo.get(el);
13357 this.el.unselectable();
13359 Roo.apply(this, config);
13364 * Fires when the mouse button is depressed.
13365 * @param {Roo.util.ClickRepeater} this
13367 "mousedown" : true,
13370 * Fires on a specified interval during the time the element is pressed.
13371 * @param {Roo.util.ClickRepeater} this
13376 * Fires when the mouse key is released.
13377 * @param {Roo.util.ClickRepeater} this
13382 this.el.on("mousedown", this.handleMouseDown, this);
13383 if(this.preventDefault || this.stopDefault){
13384 this.el.on("click", function(e){
13385 if(this.preventDefault){
13386 e.preventDefault();
13388 if(this.stopDefault){
13394 // allow inline handler
13396 this.on("click", this.handler, this.scope || this);
13399 Roo.util.ClickRepeater.superclass.constructor.call(this);
13402 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13405 preventDefault : true,
13406 stopDefault : false,
13410 handleMouseDown : function(){
13411 clearTimeout(this.timer);
13413 if(this.pressClass){
13414 this.el.addClass(this.pressClass);
13416 this.mousedownTime = new Date();
13418 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13419 this.el.on("mouseout", this.handleMouseOut, this);
13421 this.fireEvent("mousedown", this);
13422 this.fireEvent("click", this);
13424 this.timer = this.click.defer(this.delay || this.interval, this);
13428 click : function(){
13429 this.fireEvent("click", this);
13430 this.timer = this.click.defer(this.getInterval(), this);
13434 getInterval: function(){
13435 if(!this.accelerate){
13436 return this.interval;
13438 var pressTime = this.mousedownTime.getElapsed();
13439 if(pressTime < 500){
13441 }else if(pressTime < 1700){
13443 }else if(pressTime < 2600){
13445 }else if(pressTime < 3500){
13447 }else if(pressTime < 4400){
13449 }else if(pressTime < 5300){
13451 }else if(pressTime < 6200){
13459 handleMouseOut : function(){
13460 clearTimeout(this.timer);
13461 if(this.pressClass){
13462 this.el.removeClass(this.pressClass);
13464 this.el.on("mouseover", this.handleMouseReturn, this);
13468 handleMouseReturn : function(){
13469 this.el.un("mouseover", this.handleMouseReturn);
13470 if(this.pressClass){
13471 this.el.addClass(this.pressClass);
13477 handleMouseUp : function(){
13478 clearTimeout(this.timer);
13479 this.el.un("mouseover", this.handleMouseReturn);
13480 this.el.un("mouseout", this.handleMouseOut);
13481 Roo.get(document).un("mouseup", this.handleMouseUp);
13482 this.el.removeClass(this.pressClass);
13483 this.fireEvent("mouseup", this);
13487 * Ext JS Library 1.1.1
13488 * Copyright(c) 2006-2007, Ext JS, LLC.
13490 * Originally Released Under LGPL - original licence link has changed is not relivant.
13493 * <script type="text/javascript">
13498 * @class Roo.KeyNav
13499 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13500 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13501 * way to implement custom navigation schemes for any UI component.</p>
13502 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13503 * pageUp, pageDown, del, home, end. Usage:</p>
13505 var nav = new Roo.KeyNav("my-element", {
13506 "left" : function(e){
13507 this.moveLeft(e.ctrlKey);
13509 "right" : function(e){
13510 this.moveRight(e.ctrlKey);
13512 "enter" : function(e){
13519 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13520 * @param {Object} config The config
13522 Roo.KeyNav = function(el, config){
13523 this.el = Roo.get(el);
13524 Roo.apply(this, config);
13525 if(!this.disabled){
13526 this.disabled = true;
13531 Roo.KeyNav.prototype = {
13533 * @cfg {Boolean} disabled
13534 * True to disable this KeyNav instance (defaults to false)
13538 * @cfg {String} defaultEventAction
13539 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13540 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13541 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13543 defaultEventAction: "stopEvent",
13545 * @cfg {Boolean} forceKeyDown
13546 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13547 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13548 * handle keydown instead of keypress.
13550 forceKeyDown : false,
13553 prepareEvent : function(e){
13554 var k = e.getKey();
13555 var h = this.keyToHandler[k];
13556 //if(h && this[h]){
13557 // e.stopPropagation();
13559 if(Roo.isSafari && h && k >= 37 && k <= 40){
13565 relay : function(e){
13566 var k = e.getKey();
13567 var h = this.keyToHandler[k];
13569 if(this.doRelay(e, this[h], h) !== true){
13570 e[this.defaultEventAction]();
13576 doRelay : function(e, h, hname){
13577 return h.call(this.scope || this, e);
13580 // possible handlers
13594 // quick lookup hash
13611 * Enable this KeyNav
13613 enable: function(){
13615 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13616 // the EventObject will normalize Safari automatically
13617 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13618 this.el.on("keydown", this.relay, this);
13620 this.el.on("keydown", this.prepareEvent, this);
13621 this.el.on("keypress", this.relay, this);
13623 this.disabled = false;
13628 * Disable this KeyNav
13630 disable: function(){
13631 if(!this.disabled){
13632 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13633 this.el.un("keydown", this.relay);
13635 this.el.un("keydown", this.prepareEvent);
13636 this.el.un("keypress", this.relay);
13638 this.disabled = true;
13643 * Ext JS Library 1.1.1
13644 * Copyright(c) 2006-2007, Ext JS, LLC.
13646 * Originally Released Under LGPL - original licence link has changed is not relivant.
13649 * <script type="text/javascript">
13654 * @class Roo.KeyMap
13655 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13656 * The constructor accepts the same config object as defined by {@link #addBinding}.
13657 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13658 * combination it will call the function with this signature (if the match is a multi-key
13659 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13660 * A KeyMap can also handle a string representation of keys.<br />
13663 // map one key by key code
13664 var map = new Roo.KeyMap("my-element", {
13665 key: 13, // or Roo.EventObject.ENTER
13670 // map multiple keys to one action by string
13671 var map = new Roo.KeyMap("my-element", {
13677 // map multiple keys to multiple actions by strings and array of codes
13678 var map = new Roo.KeyMap("my-element", [
13681 fn: function(){ alert("Return was pressed"); }
13684 fn: function(){ alert('a, b or c was pressed'); }
13689 fn: function(){ alert('Control + shift + tab was pressed.'); }
13693 * <b>Note: A KeyMap starts enabled</b>
13695 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13696 * @param {Object} config The config (see {@link #addBinding})
13697 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13699 Roo.KeyMap = function(el, config, eventName){
13700 this.el = Roo.get(el);
13701 this.eventName = eventName || "keydown";
13702 this.bindings = [];
13704 this.addBinding(config);
13709 Roo.KeyMap.prototype = {
13711 * True to stop the event from bubbling and prevent the default browser action if the
13712 * key was handled by the KeyMap (defaults to false)
13718 * Add a new binding to this KeyMap. The following config object properties are supported:
13720 Property Type Description
13721 ---------- --------------- ----------------------------------------------------------------------
13722 key String/Array A single keycode or an array of keycodes to handle
13723 shift Boolean True to handle key only when shift is pressed (defaults to false)
13724 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13725 alt Boolean True to handle key only when alt is pressed (defaults to false)
13726 fn Function The function to call when KeyMap finds the expected key combination
13727 scope Object The scope of the callback function
13733 var map = new Roo.KeyMap(document, {
13734 key: Roo.EventObject.ENTER,
13739 //Add a new binding to the existing KeyMap later
13747 * @param {Object/Array} config A single KeyMap config or an array of configs
13749 addBinding : function(config){
13750 if(config instanceof Array){
13751 for(var i = 0, len = config.length; i < len; i++){
13752 this.addBinding(config[i]);
13756 var keyCode = config.key,
13757 shift = config.shift,
13758 ctrl = config.ctrl,
13761 scope = config.scope;
13762 if(typeof keyCode == "string"){
13764 var keyString = keyCode.toUpperCase();
13765 for(var j = 0, len = keyString.length; j < len; j++){
13766 ks.push(keyString.charCodeAt(j));
13770 var keyArray = keyCode instanceof Array;
13771 var handler = function(e){
13772 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13773 var k = e.getKey();
13775 for(var i = 0, len = keyCode.length; i < len; i++){
13776 if(keyCode[i] == k){
13777 if(this.stopEvent){
13780 fn.call(scope || window, k, e);
13786 if(this.stopEvent){
13789 fn.call(scope || window, k, e);
13794 this.bindings.push(handler);
13798 * Shorthand for adding a single key listener
13799 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13800 * following options:
13801 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13802 * @param {Function} fn The function to call
13803 * @param {Object} scope (optional) The scope of the function
13805 on : function(key, fn, scope){
13806 var keyCode, shift, ctrl, alt;
13807 if(typeof key == "object" && !(key instanceof Array)){
13826 handleKeyDown : function(e){
13827 if(this.enabled){ //just in case
13828 var b = this.bindings;
13829 for(var i = 0, len = b.length; i < len; i++){
13830 b[i].call(this, e);
13836 * Returns true if this KeyMap is enabled
13837 * @return {Boolean}
13839 isEnabled : function(){
13840 return this.enabled;
13844 * Enables this KeyMap
13846 enable: function(){
13848 this.el.on(this.eventName, this.handleKeyDown, this);
13849 this.enabled = true;
13854 * Disable this KeyMap
13856 disable: function(){
13858 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13859 this.enabled = false;
13864 * Ext JS Library 1.1.1
13865 * Copyright(c) 2006-2007, Ext JS, LLC.
13867 * Originally Released Under LGPL - original licence link has changed is not relivant.
13870 * <script type="text/javascript">
13875 * @class Roo.util.TextMetrics
13876 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13877 * wide, in pixels, a given block of text will be.
13880 Roo.util.TextMetrics = function(){
13884 * Measures the size of the specified text
13885 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13886 * that can affect the size of the rendered text
13887 * @param {String} text The text to measure
13888 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13889 * in order to accurately measure the text height
13890 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13892 measure : function(el, text, fixedWidth){
13894 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13897 shared.setFixedWidth(fixedWidth || 'auto');
13898 return shared.getSize(text);
13902 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13903 * the overhead of multiple calls to initialize the style properties on each measurement.
13904 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13905 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13906 * in order to accurately measure the text height
13907 * @return {Roo.util.TextMetrics.Instance} instance The new instance
13909 createInstance : function(el, fixedWidth){
13910 return Roo.util.TextMetrics.Instance(el, fixedWidth);
13917 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13918 var ml = new Roo.Element(document.createElement('div'));
13919 document.body.appendChild(ml.dom);
13920 ml.position('absolute');
13921 ml.setLeftTop(-1000, -1000);
13925 ml.setWidth(fixedWidth);
13930 * Returns the size of the specified text based on the internal element's style and width properties
13931 * @memberOf Roo.util.TextMetrics.Instance#
13932 * @param {String} text The text to measure
13933 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13935 getSize : function(text){
13937 var s = ml.getSize();
13943 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13944 * that can affect the size of the rendered text
13945 * @memberOf Roo.util.TextMetrics.Instance#
13946 * @param {String/HTMLElement} el The element, dom node or id
13948 bind : function(el){
13950 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13955 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
13956 * to set a fixed width in order to accurately measure the text height.
13957 * @memberOf Roo.util.TextMetrics.Instance#
13958 * @param {Number} width The width to set on the element
13960 setFixedWidth : function(width){
13961 ml.setWidth(width);
13965 * Returns the measured width of the specified text
13966 * @memberOf Roo.util.TextMetrics.Instance#
13967 * @param {String} text The text to measure
13968 * @return {Number} width The width in pixels
13970 getWidth : function(text){
13971 ml.dom.style.width = 'auto';
13972 return this.getSize(text).width;
13976 * Returns the measured height of the specified text. For multiline text, be sure to call
13977 * {@link #setFixedWidth} if necessary.
13978 * @memberOf Roo.util.TextMetrics.Instance#
13979 * @param {String} text The text to measure
13980 * @return {Number} height The height in pixels
13982 getHeight : function(text){
13983 return this.getSize(text).height;
13987 instance.bind(bindTo);
13992 // backwards compat
13993 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13995 * Ext JS Library 1.1.1
13996 * Copyright(c) 2006-2007, Ext JS, LLC.
13998 * Originally Released Under LGPL - original licence link has changed is not relivant.
14001 * <script type="text/javascript">
14005 * @class Roo.state.Provider
14006 * Abstract base class for state provider implementations. This class provides methods
14007 * for encoding and decoding <b>typed</b> variables including dates and defines the
14008 * Provider interface.
14010 Roo.state.Provider = function(){
14012 * @event statechange
14013 * Fires when a state change occurs.
14014 * @param {Provider} this This state provider
14015 * @param {String} key The state key which was changed
14016 * @param {String} value The encoded value for the state
14019 "statechange": true
14022 Roo.state.Provider.superclass.constructor.call(this);
14024 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14026 * Returns the current value for a key
14027 * @param {String} name The key name
14028 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14029 * @return {Mixed} The state data
14031 get : function(name, defaultValue){
14032 return typeof this.state[name] == "undefined" ?
14033 defaultValue : this.state[name];
14037 * Clears a value from the state
14038 * @param {String} name The key name
14040 clear : function(name){
14041 delete this.state[name];
14042 this.fireEvent("statechange", this, name, null);
14046 * Sets the value for a key
14047 * @param {String} name The key name
14048 * @param {Mixed} value The value to set
14050 set : function(name, value){
14051 this.state[name] = value;
14052 this.fireEvent("statechange", this, name, value);
14056 * Decodes a string previously encoded with {@link #encodeValue}.
14057 * @param {String} value The value to decode
14058 * @return {Mixed} The decoded value
14060 decodeValue : function(cookie){
14061 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14062 var matches = re.exec(unescape(cookie));
14063 if(!matches || !matches[1]) return; // non state cookie
14064 var type = matches[1];
14065 var v = matches[2];
14068 return parseFloat(v);
14070 return new Date(Date.parse(v));
14075 var values = v.split("^");
14076 for(var i = 0, len = values.length; i < len; i++){
14077 all.push(this.decodeValue(values[i]));
14082 var values = v.split("^");
14083 for(var i = 0, len = values.length; i < len; i++){
14084 var kv = values[i].split("=");
14085 all[kv[0]] = this.decodeValue(kv[1]);
14094 * Encodes a value including type information. Decode with {@link #decodeValue}.
14095 * @param {Mixed} value The value to encode
14096 * @return {String} The encoded value
14098 encodeValue : function(v){
14100 if(typeof v == "number"){
14102 }else if(typeof v == "boolean"){
14103 enc = "b:" + (v ? "1" : "0");
14104 }else if(v instanceof Date){
14105 enc = "d:" + v.toGMTString();
14106 }else if(v instanceof Array){
14108 for(var i = 0, len = v.length; i < len; i++){
14109 flat += this.encodeValue(v[i]);
14110 if(i != len-1) flat += "^";
14113 }else if(typeof v == "object"){
14116 if(typeof v[key] != "function"){
14117 flat += key + "=" + this.encodeValue(v[key]) + "^";
14120 enc = "o:" + flat.substring(0, flat.length-1);
14124 return escape(enc);
14130 * Ext JS Library 1.1.1
14131 * Copyright(c) 2006-2007, Ext JS, LLC.
14133 * Originally Released Under LGPL - original licence link has changed is not relivant.
14136 * <script type="text/javascript">
14139 * @class Roo.state.Manager
14140 * This is the global state manager. By default all components that are "state aware" check this class
14141 * for state information if you don't pass them a custom state provider. In order for this class
14142 * to be useful, it must be initialized with a provider when your application initializes.
14144 // in your initialization function
14146 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14148 // supposed you have a {@link Roo.BorderLayout}
14149 var layout = new Roo.BorderLayout(...);
14150 layout.restoreState();
14151 // or a {Roo.BasicDialog}
14152 var dialog = new Roo.BasicDialog(...);
14153 dialog.restoreState();
14157 Roo.state.Manager = function(){
14158 var provider = new Roo.state.Provider();
14162 * Configures the default state provider for your application
14163 * @param {Provider} stateProvider The state provider to set
14165 setProvider : function(stateProvider){
14166 provider = stateProvider;
14170 * Returns the current value for a key
14171 * @param {String} name The key name
14172 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14173 * @return {Mixed} The state data
14175 get : function(key, defaultValue){
14176 return provider.get(key, defaultValue);
14180 * Sets the value for a key
14181 * @param {String} name The key name
14182 * @param {Mixed} value The state data
14184 set : function(key, value){
14185 provider.set(key, value);
14189 * Clears a value from the state
14190 * @param {String} name The key name
14192 clear : function(key){
14193 provider.clear(key);
14197 * Gets the currently configured state provider
14198 * @return {Provider} The state provider
14200 getProvider : function(){
14207 * Ext JS Library 1.1.1
14208 * Copyright(c) 2006-2007, Ext JS, LLC.
14210 * Originally Released Under LGPL - original licence link has changed is not relivant.
14213 * <script type="text/javascript">
14216 * @class Roo.state.CookieProvider
14217 * @extends Roo.state.Provider
14218 * The default Provider implementation which saves state via cookies.
14221 var cp = new Roo.state.CookieProvider({
14223 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14224 domain: "roojs.com"
14226 Roo.state.Manager.setProvider(cp);
14228 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14229 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14230 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14231 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14232 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14233 * domain the page is running on including the 'www' like 'www.roojs.com')
14234 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14236 * Create a new CookieProvider
14237 * @param {Object} config The configuration object
14239 Roo.state.CookieProvider = function(config){
14240 Roo.state.CookieProvider.superclass.constructor.call(this);
14242 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14243 this.domain = null;
14244 this.secure = false;
14245 Roo.apply(this, config);
14246 this.state = this.readCookies();
14249 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14251 set : function(name, value){
14252 if(typeof value == "undefined" || value === null){
14256 this.setCookie(name, value);
14257 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14261 clear : function(name){
14262 this.clearCookie(name);
14263 Roo.state.CookieProvider.superclass.clear.call(this, name);
14267 readCookies : function(){
14269 var c = document.cookie + ";";
14270 var re = /\s?(.*?)=(.*?);/g;
14272 while((matches = re.exec(c)) != null){
14273 var name = matches[1];
14274 var value = matches[2];
14275 if(name && name.substring(0,3) == "ys-"){
14276 cookies[name.substr(3)] = this.decodeValue(value);
14283 setCookie : function(name, value){
14284 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14285 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14286 ((this.path == null) ? "" : ("; path=" + this.path)) +
14287 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14288 ((this.secure == true) ? "; secure" : "");
14292 clearCookie : function(name){
14293 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14294 ((this.path == null) ? "" : ("; path=" + this.path)) +
14295 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14296 ((this.secure == true) ? "; secure" : "");
14300 * Ext JS Library 1.1.1
14301 * Copyright(c) 2006-2007, Ext JS, LLC.
14303 * Originally Released Under LGPL - original licence link has changed is not relivant.
14306 * <script type="text/javascript">
14312 * These classes are derivatives of the similarly named classes in the YUI Library.
14313 * The original license:
14314 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14315 * Code licensed under the BSD License:
14316 * http://developer.yahoo.net/yui/license.txt
14321 var Event=Roo.EventManager;
14322 var Dom=Roo.lib.Dom;
14325 * @class Roo.dd.DragDrop
14326 * Defines the interface and base operation of items that that can be
14327 * dragged or can be drop targets. It was designed to be extended, overriding
14328 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14329 * Up to three html elements can be associated with a DragDrop instance:
14331 * <li>linked element: the element that is passed into the constructor.
14332 * This is the element which defines the boundaries for interaction with
14333 * other DragDrop objects.</li>
14334 * <li>handle element(s): The drag operation only occurs if the element that
14335 * was clicked matches a handle element. By default this is the linked
14336 * element, but there are times that you will want only a portion of the
14337 * linked element to initiate the drag operation, and the setHandleElId()
14338 * method provides a way to define this.</li>
14339 * <li>drag element: this represents the element that would be moved along
14340 * with the cursor during a drag operation. By default, this is the linked
14341 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14342 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14345 * This class should not be instantiated until the onload event to ensure that
14346 * the associated elements are available.
14347 * The following would define a DragDrop obj that would interact with any
14348 * other DragDrop obj in the "group1" group:
14350 * dd = new Roo.dd.DragDrop("div1", "group1");
14352 * Since none of the event handlers have been implemented, nothing would
14353 * actually happen if you were to run the code above. Normally you would
14354 * override this class or one of the default implementations, but you can
14355 * also override the methods you want on an instance of the class...
14357 * dd.onDragDrop = function(e, id) {
14358 * alert("dd was dropped on " + id);
14362 * @param {String} id of the element that is linked to this instance
14363 * @param {String} sGroup the group of related DragDrop objects
14364 * @param {object} config an object containing configurable attributes
14365 * Valid properties for DragDrop:
14366 * padding, isTarget, maintainOffset, primaryButtonOnly
14368 Roo.dd.DragDrop = function(id, sGroup, config) {
14370 this.init(id, sGroup, config);
14374 Roo.dd.DragDrop.prototype = {
14377 * The id of the element associated with this object. This is what we
14378 * refer to as the "linked element" because the size and position of
14379 * this element is used to determine when the drag and drop objects have
14387 * Configuration attributes passed into the constructor
14394 * The id of the element that will be dragged. By default this is same
14395 * as the linked element , but could be changed to another element. Ex:
14397 * @property dragElId
14404 * the id of the element that initiates the drag operation. By default
14405 * this is the linked element, but could be changed to be a child of this
14406 * element. This lets us do things like only starting the drag when the
14407 * header element within the linked html element is clicked.
14408 * @property handleElId
14415 * An associative array of HTML tags that will be ignored if clicked.
14416 * @property invalidHandleTypes
14417 * @type {string: string}
14419 invalidHandleTypes: null,
14422 * An associative array of ids for elements that will be ignored if clicked
14423 * @property invalidHandleIds
14424 * @type {string: string}
14426 invalidHandleIds: null,
14429 * An indexted array of css class names for elements that will be ignored
14431 * @property invalidHandleClasses
14434 invalidHandleClasses: null,
14437 * The linked element's absolute X position at the time the drag was
14439 * @property startPageX
14446 * The linked element's absolute X position at the time the drag was
14448 * @property startPageY
14455 * The group defines a logical collection of DragDrop objects that are
14456 * related. Instances only get events when interacting with other
14457 * DragDrop object in the same group. This lets us define multiple
14458 * groups using a single DragDrop subclass if we want.
14460 * @type {string: string}
14465 * Individual drag/drop instances can be locked. This will prevent
14466 * onmousedown start drag.
14474 * Lock this instance
14477 lock: function() { this.locked = true; },
14480 * Unlock this instace
14483 unlock: function() { this.locked = false; },
14486 * By default, all insances can be a drop target. This can be disabled by
14487 * setting isTarget to false.
14494 * The padding configured for this drag and drop object for calculating
14495 * the drop zone intersection with this object.
14502 * Cached reference to the linked element
14503 * @property _domRef
14509 * Internal typeof flag
14510 * @property __ygDragDrop
14513 __ygDragDrop: true,
14516 * Set to true when horizontal contraints are applied
14517 * @property constrainX
14524 * Set to true when vertical contraints are applied
14525 * @property constrainY
14532 * The left constraint
14540 * The right constraint
14548 * The up constraint
14557 * The down constraint
14565 * Maintain offsets when we resetconstraints. Set to true when you want
14566 * the position of the element relative to its parent to stay the same
14567 * when the page changes
14569 * @property maintainOffset
14572 maintainOffset: false,
14575 * Array of pixel locations the element will snap to if we specified a
14576 * horizontal graduation/interval. This array is generated automatically
14577 * when you define a tick interval.
14584 * Array of pixel locations the element will snap to if we specified a
14585 * vertical graduation/interval. This array is generated automatically
14586 * when you define a tick interval.
14593 * By default the drag and drop instance will only respond to the primary
14594 * button click (left button for a right-handed mouse). Set to true to
14595 * allow drag and drop to start with any mouse click that is propogated
14597 * @property primaryButtonOnly
14600 primaryButtonOnly: true,
14603 * The availabe property is false until the linked dom element is accessible.
14604 * @property available
14610 * By default, drags can only be initiated if the mousedown occurs in the
14611 * region the linked element is. This is done in part to work around a
14612 * bug in some browsers that mis-report the mousedown if the previous
14613 * mouseup happened outside of the window. This property is set to true
14614 * if outer handles are defined.
14616 * @property hasOuterHandles
14620 hasOuterHandles: false,
14623 * Code that executes immediately before the startDrag event
14624 * @method b4StartDrag
14627 b4StartDrag: function(x, y) { },
14630 * Abstract method called after a drag/drop object is clicked
14631 * and the drag or mousedown time thresholds have beeen met.
14632 * @method startDrag
14633 * @param {int} X click location
14634 * @param {int} Y click location
14636 startDrag: function(x, y) { /* override this */ },
14639 * Code that executes immediately before the onDrag event
14643 b4Drag: function(e) { },
14646 * Abstract method called during the onMouseMove event while dragging an
14649 * @param {Event} e the mousemove event
14651 onDrag: function(e) { /* override this */ },
14654 * Abstract method called when this element fist begins hovering over
14655 * another DragDrop obj
14656 * @method onDragEnter
14657 * @param {Event} e the mousemove event
14658 * @param {String|DragDrop[]} id In POINT mode, the element
14659 * id this is hovering over. In INTERSECT mode, an array of one or more
14660 * dragdrop items being hovered over.
14662 onDragEnter: function(e, id) { /* override this */ },
14665 * Code that executes immediately before the onDragOver event
14666 * @method b4DragOver
14669 b4DragOver: function(e) { },
14672 * Abstract method called when this element is hovering over another
14674 * @method onDragOver
14675 * @param {Event} e the mousemove event
14676 * @param {String|DragDrop[]} id In POINT mode, the element
14677 * id this is hovering over. In INTERSECT mode, an array of dd items
14678 * being hovered over.
14680 onDragOver: function(e, id) { /* override this */ },
14683 * Code that executes immediately before the onDragOut event
14684 * @method b4DragOut
14687 b4DragOut: function(e) { },
14690 * Abstract method called when we are no longer hovering over an element
14691 * @method onDragOut
14692 * @param {Event} e the mousemove event
14693 * @param {String|DragDrop[]} id In POINT mode, the element
14694 * id this was hovering over. In INTERSECT mode, an array of dd items
14695 * that the mouse is no longer over.
14697 onDragOut: function(e, id) { /* override this */ },
14700 * Code that executes immediately before the onDragDrop event
14701 * @method b4DragDrop
14704 b4DragDrop: function(e) { },
14707 * Abstract method called when this item is dropped on another DragDrop
14709 * @method onDragDrop
14710 * @param {Event} e the mouseup event
14711 * @param {String|DragDrop[]} id In POINT mode, the element
14712 * id this was dropped on. In INTERSECT mode, an array of dd items this
14715 onDragDrop: function(e, id) { /* override this */ },
14718 * Abstract method called when this item is dropped on an area with no
14720 * @method onInvalidDrop
14721 * @param {Event} e the mouseup event
14723 onInvalidDrop: function(e) { /* override this */ },
14726 * Code that executes immediately before the endDrag event
14727 * @method b4EndDrag
14730 b4EndDrag: function(e) { },
14733 * Fired when we are done dragging the object
14735 * @param {Event} e the mouseup event
14737 endDrag: function(e) { /* override this */ },
14740 * Code executed immediately before the onMouseDown event
14741 * @method b4MouseDown
14742 * @param {Event} e the mousedown event
14745 b4MouseDown: function(e) { },
14748 * Event handler that fires when a drag/drop obj gets a mousedown
14749 * @method onMouseDown
14750 * @param {Event} e the mousedown event
14752 onMouseDown: function(e) { /* override this */ },
14755 * Event handler that fires when a drag/drop obj gets a mouseup
14756 * @method onMouseUp
14757 * @param {Event} e the mouseup event
14759 onMouseUp: function(e) { /* override this */ },
14762 * Override the onAvailable method to do what is needed after the initial
14763 * position was determined.
14764 * @method onAvailable
14766 onAvailable: function () {
14770 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14773 defaultPadding : {left:0, right:0, top:0, bottom:0},
14776 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14780 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14781 { dragElId: "existingProxyDiv" });
14782 dd.startDrag = function(){
14783 this.constrainTo("parent-id");
14786 * Or you can initalize it using the {@link Roo.Element} object:
14788 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14789 startDrag : function(){
14790 this.constrainTo("parent-id");
14794 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14795 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14796 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14797 * an object containing the sides to pad. For example: {right:10, bottom:10}
14798 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14800 constrainTo : function(constrainTo, pad, inContent){
14801 if(typeof pad == "number"){
14802 pad = {left: pad, right:pad, top:pad, bottom:pad};
14804 pad = pad || this.defaultPadding;
14805 var b = Roo.get(this.getEl()).getBox();
14806 var ce = Roo.get(constrainTo);
14807 var s = ce.getScroll();
14808 var c, cd = ce.dom;
14809 if(cd == document.body){
14810 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14813 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14817 var topSpace = b.y - c.y;
14818 var leftSpace = b.x - c.x;
14820 this.resetConstraints();
14821 this.setXConstraint(leftSpace - (pad.left||0), // left
14822 c.width - leftSpace - b.width - (pad.right||0) //right
14824 this.setYConstraint(topSpace - (pad.top||0), //top
14825 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14830 * Returns a reference to the linked element
14832 * @return {HTMLElement} the html element
14834 getEl: function() {
14835 if (!this._domRef) {
14836 this._domRef = Roo.getDom(this.id);
14839 return this._domRef;
14843 * Returns a reference to the actual element to drag. By default this is
14844 * the same as the html element, but it can be assigned to another
14845 * element. An example of this can be found in Roo.dd.DDProxy
14846 * @method getDragEl
14847 * @return {HTMLElement} the html element
14849 getDragEl: function() {
14850 return Roo.getDom(this.dragElId);
14854 * Sets up the DragDrop object. Must be called in the constructor of any
14855 * Roo.dd.DragDrop subclass
14857 * @param id the id of the linked element
14858 * @param {String} sGroup the group of related items
14859 * @param {object} config configuration attributes
14861 init: function(id, sGroup, config) {
14862 this.initTarget(id, sGroup, config);
14863 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14864 // Event.on(this.id, "selectstart", Event.preventDefault);
14868 * Initializes Targeting functionality only... the object does not
14869 * get a mousedown handler.
14870 * @method initTarget
14871 * @param id the id of the linked element
14872 * @param {String} sGroup the group of related items
14873 * @param {object} config configuration attributes
14875 initTarget: function(id, sGroup, config) {
14877 // configuration attributes
14878 this.config = config || {};
14880 // create a local reference to the drag and drop manager
14881 this.DDM = Roo.dd.DDM;
14882 // initialize the groups array
14885 // assume that we have an element reference instead of an id if the
14886 // parameter is not a string
14887 if (typeof id !== "string") {
14894 // add to an interaction group
14895 this.addToGroup((sGroup) ? sGroup : "default");
14897 // We don't want to register this as the handle with the manager
14898 // so we just set the id rather than calling the setter.
14899 this.handleElId = id;
14901 // the linked element is the element that gets dragged by default
14902 this.setDragElId(id);
14904 // by default, clicked anchors will not start drag operations.
14905 this.invalidHandleTypes = { A: "A" };
14906 this.invalidHandleIds = {};
14907 this.invalidHandleClasses = [];
14909 this.applyConfig();
14911 this.handleOnAvailable();
14915 * Applies the configuration parameters that were passed into the constructor.
14916 * This is supposed to happen at each level through the inheritance chain. So
14917 * a DDProxy implentation will execute apply config on DDProxy, DD, and
14918 * DragDrop in order to get all of the parameters that are available in
14920 * @method applyConfig
14922 applyConfig: function() {
14924 // configurable properties:
14925 // padding, isTarget, maintainOffset, primaryButtonOnly
14926 this.padding = this.config.padding || [0, 0, 0, 0];
14927 this.isTarget = (this.config.isTarget !== false);
14928 this.maintainOffset = (this.config.maintainOffset);
14929 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
14934 * Executed when the linked element is available
14935 * @method handleOnAvailable
14938 handleOnAvailable: function() {
14939 this.available = true;
14940 this.resetConstraints();
14941 this.onAvailable();
14945 * Configures the padding for the target zone in px. Effectively expands
14946 * (or reduces) the virtual object size for targeting calculations.
14947 * Supports css-style shorthand; if only one parameter is passed, all sides
14948 * will have that padding, and if only two are passed, the top and bottom
14949 * will have the first param, the left and right the second.
14950 * @method setPadding
14951 * @param {int} iTop Top pad
14952 * @param {int} iRight Right pad
14953 * @param {int} iBot Bot pad
14954 * @param {int} iLeft Left pad
14956 setPadding: function(iTop, iRight, iBot, iLeft) {
14957 // this.padding = [iLeft, iRight, iTop, iBot];
14958 if (!iRight && 0 !== iRight) {
14959 this.padding = [iTop, iTop, iTop, iTop];
14960 } else if (!iBot && 0 !== iBot) {
14961 this.padding = [iTop, iRight, iTop, iRight];
14963 this.padding = [iTop, iRight, iBot, iLeft];
14968 * Stores the initial placement of the linked element.
14969 * @method setInitialPosition
14970 * @param {int} diffX the X offset, default 0
14971 * @param {int} diffY the Y offset, default 0
14973 setInitPosition: function(diffX, diffY) {
14974 var el = this.getEl();
14976 if (!this.DDM.verifyEl(el)) {
14980 var dx = diffX || 0;
14981 var dy = diffY || 0;
14983 var p = Dom.getXY( el );
14985 this.initPageX = p[0] - dx;
14986 this.initPageY = p[1] - dy;
14988 this.lastPageX = p[0];
14989 this.lastPageY = p[1];
14992 this.setStartPosition(p);
14996 * Sets the start position of the element. This is set when the obj
14997 * is initialized, the reset when a drag is started.
14998 * @method setStartPosition
14999 * @param pos current position (from previous lookup)
15002 setStartPosition: function(pos) {
15003 var p = pos || Dom.getXY( this.getEl() );
15004 this.deltaSetXY = null;
15006 this.startPageX = p[0];
15007 this.startPageY = p[1];
15011 * Add this instance to a group of related drag/drop objects. All
15012 * instances belong to at least one group, and can belong to as many
15013 * groups as needed.
15014 * @method addToGroup
15015 * @param sGroup {string} the name of the group
15017 addToGroup: function(sGroup) {
15018 this.groups[sGroup] = true;
15019 this.DDM.regDragDrop(this, sGroup);
15023 * Remove's this instance from the supplied interaction group
15024 * @method removeFromGroup
15025 * @param {string} sGroup The group to drop
15027 removeFromGroup: function(sGroup) {
15028 if (this.groups[sGroup]) {
15029 delete this.groups[sGroup];
15032 this.DDM.removeDDFromGroup(this, sGroup);
15036 * Allows you to specify that an element other than the linked element
15037 * will be moved with the cursor during a drag
15038 * @method setDragElId
15039 * @param id {string} the id of the element that will be used to initiate the drag
15041 setDragElId: function(id) {
15042 this.dragElId = id;
15046 * Allows you to specify a child of the linked element that should be
15047 * used to initiate the drag operation. An example of this would be if
15048 * you have a content div with text and links. Clicking anywhere in the
15049 * content area would normally start the drag operation. Use this method
15050 * to specify that an element inside of the content div is the element
15051 * that starts the drag operation.
15052 * @method setHandleElId
15053 * @param id {string} the id of the element that will be used to
15054 * initiate the drag.
15056 setHandleElId: function(id) {
15057 if (typeof id !== "string") {
15060 this.handleElId = id;
15061 this.DDM.regHandle(this.id, id);
15065 * Allows you to set an element outside of the linked element as a drag
15067 * @method setOuterHandleElId
15068 * @param id the id of the element that will be used to initiate the drag
15070 setOuterHandleElId: function(id) {
15071 if (typeof id !== "string") {
15074 Event.on(id, "mousedown",
15075 this.handleMouseDown, this);
15076 this.setHandleElId(id);
15078 this.hasOuterHandles = true;
15082 * Remove all drag and drop hooks for this element
15085 unreg: function() {
15086 Event.un(this.id, "mousedown",
15087 this.handleMouseDown);
15088 this._domRef = null;
15089 this.DDM._remove(this);
15092 destroy : function(){
15097 * Returns true if this instance is locked, or the drag drop mgr is locked
15098 * (meaning that all drag/drop is disabled on the page.)
15100 * @return {boolean} true if this obj or all drag/drop is locked, else
15103 isLocked: function() {
15104 return (this.DDM.isLocked() || this.locked);
15108 * Fired when this object is clicked
15109 * @method handleMouseDown
15111 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15114 handleMouseDown: function(e, oDD){
15115 if (this.primaryButtonOnly && e.button != 0) {
15119 if (this.isLocked()) {
15123 this.DDM.refreshCache(this.groups);
15125 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15126 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15128 if (this.clickValidator(e)) {
15130 // set the initial element position
15131 this.setStartPosition();
15134 this.b4MouseDown(e);
15135 this.onMouseDown(e);
15137 this.DDM.handleMouseDown(e, this);
15139 this.DDM.stopEvent(e);
15147 clickValidator: function(e) {
15148 var target = e.getTarget();
15149 return ( this.isValidHandleChild(target) &&
15150 (this.id == this.handleElId ||
15151 this.DDM.handleWasClicked(target, this.id)) );
15155 * Allows you to specify a tag name that should not start a drag operation
15156 * when clicked. This is designed to facilitate embedding links within a
15157 * drag handle that do something other than start the drag.
15158 * @method addInvalidHandleType
15159 * @param {string} tagName the type of element to exclude
15161 addInvalidHandleType: function(tagName) {
15162 var type = tagName.toUpperCase();
15163 this.invalidHandleTypes[type] = type;
15167 * Lets you to specify an element id for a child of a drag handle
15168 * that should not initiate a drag
15169 * @method addInvalidHandleId
15170 * @param {string} id the element id of the element you wish to ignore
15172 addInvalidHandleId: function(id) {
15173 if (typeof id !== "string") {
15176 this.invalidHandleIds[id] = id;
15180 * Lets you specify a css class of elements that will not initiate a drag
15181 * @method addInvalidHandleClass
15182 * @param {string} cssClass the class of the elements you wish to ignore
15184 addInvalidHandleClass: function(cssClass) {
15185 this.invalidHandleClasses.push(cssClass);
15189 * Unsets an excluded tag name set by addInvalidHandleType
15190 * @method removeInvalidHandleType
15191 * @param {string} tagName the type of element to unexclude
15193 removeInvalidHandleType: function(tagName) {
15194 var type = tagName.toUpperCase();
15195 // this.invalidHandleTypes[type] = null;
15196 delete this.invalidHandleTypes[type];
15200 * Unsets an invalid handle id
15201 * @method removeInvalidHandleId
15202 * @param {string} id the id of the element to re-enable
15204 removeInvalidHandleId: function(id) {
15205 if (typeof id !== "string") {
15208 delete this.invalidHandleIds[id];
15212 * Unsets an invalid css class
15213 * @method removeInvalidHandleClass
15214 * @param {string} cssClass the class of the element(s) you wish to
15217 removeInvalidHandleClass: function(cssClass) {
15218 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15219 if (this.invalidHandleClasses[i] == cssClass) {
15220 delete this.invalidHandleClasses[i];
15226 * Checks the tag exclusion list to see if this click should be ignored
15227 * @method isValidHandleChild
15228 * @param {HTMLElement} node the HTMLElement to evaluate
15229 * @return {boolean} true if this is a valid tag type, false if not
15231 isValidHandleChild: function(node) {
15234 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15237 nodeName = node.nodeName.toUpperCase();
15239 nodeName = node.nodeName;
15241 valid = valid && !this.invalidHandleTypes[nodeName];
15242 valid = valid && !this.invalidHandleIds[node.id];
15244 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15245 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15254 * Create the array of horizontal tick marks if an interval was specified
15255 * in setXConstraint().
15256 * @method setXTicks
15259 setXTicks: function(iStartX, iTickSize) {
15261 this.xTickSize = iTickSize;
15265 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15267 this.xTicks[this.xTicks.length] = i;
15272 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15274 this.xTicks[this.xTicks.length] = i;
15279 this.xTicks.sort(this.DDM.numericSort) ;
15283 * Create the array of vertical tick marks if an interval was specified in
15284 * setYConstraint().
15285 * @method setYTicks
15288 setYTicks: function(iStartY, iTickSize) {
15290 this.yTickSize = iTickSize;
15294 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15296 this.yTicks[this.yTicks.length] = i;
15301 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15303 this.yTicks[this.yTicks.length] = i;
15308 this.yTicks.sort(this.DDM.numericSort) ;
15312 * By default, the element can be dragged any place on the screen. Use
15313 * this method to limit the horizontal travel of the element. Pass in
15314 * 0,0 for the parameters if you want to lock the drag to the y axis.
15315 * @method setXConstraint
15316 * @param {int} iLeft the number of pixels the element can move to the left
15317 * @param {int} iRight the number of pixels the element can move to the
15319 * @param {int} iTickSize optional parameter for specifying that the
15321 * should move iTickSize pixels at a time.
15323 setXConstraint: function(iLeft, iRight, iTickSize) {
15324 this.leftConstraint = iLeft;
15325 this.rightConstraint = iRight;
15327 this.minX = this.initPageX - iLeft;
15328 this.maxX = this.initPageX + iRight;
15329 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15331 this.constrainX = true;
15335 * Clears any constraints applied to this instance. Also clears ticks
15336 * since they can't exist independent of a constraint at this time.
15337 * @method clearConstraints
15339 clearConstraints: function() {
15340 this.constrainX = false;
15341 this.constrainY = false;
15346 * Clears any tick interval defined for this instance
15347 * @method clearTicks
15349 clearTicks: function() {
15350 this.xTicks = null;
15351 this.yTicks = null;
15352 this.xTickSize = 0;
15353 this.yTickSize = 0;
15357 * By default, the element can be dragged any place on the screen. Set
15358 * this to limit the vertical travel of the element. Pass in 0,0 for the
15359 * parameters if you want to lock the drag to the x axis.
15360 * @method setYConstraint
15361 * @param {int} iUp the number of pixels the element can move up
15362 * @param {int} iDown the number of pixels the element can move down
15363 * @param {int} iTickSize optional parameter for specifying that the
15364 * element should move iTickSize pixels at a time.
15366 setYConstraint: function(iUp, iDown, iTickSize) {
15367 this.topConstraint = iUp;
15368 this.bottomConstraint = iDown;
15370 this.minY = this.initPageY - iUp;
15371 this.maxY = this.initPageY + iDown;
15372 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15374 this.constrainY = true;
15379 * resetConstraints must be called if you manually reposition a dd element.
15380 * @method resetConstraints
15381 * @param {boolean} maintainOffset
15383 resetConstraints: function() {
15386 // Maintain offsets if necessary
15387 if (this.initPageX || this.initPageX === 0) {
15388 // figure out how much this thing has moved
15389 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15390 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15392 this.setInitPosition(dx, dy);
15394 // This is the first time we have detected the element's position
15396 this.setInitPosition();
15399 if (this.constrainX) {
15400 this.setXConstraint( this.leftConstraint,
15401 this.rightConstraint,
15405 if (this.constrainY) {
15406 this.setYConstraint( this.topConstraint,
15407 this.bottomConstraint,
15413 * Normally the drag element is moved pixel by pixel, but we can specify
15414 * that it move a number of pixels at a time. This method resolves the
15415 * location when we have it set up like this.
15417 * @param {int} val where we want to place the object
15418 * @param {int[]} tickArray sorted array of valid points
15419 * @return {int} the closest tick
15422 getTick: function(val, tickArray) {
15425 // If tick interval is not defined, it is effectively 1 pixel,
15426 // so we return the value passed to us.
15428 } else if (tickArray[0] >= val) {
15429 // The value is lower than the first tick, so we return the first
15431 return tickArray[0];
15433 for (var i=0, len=tickArray.length; i<len; ++i) {
15435 if (tickArray[next] && tickArray[next] >= val) {
15436 var diff1 = val - tickArray[i];
15437 var diff2 = tickArray[next] - val;
15438 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15442 // The value is larger than the last tick, so we return the last
15444 return tickArray[tickArray.length - 1];
15451 * @return {string} string representation of the dd obj
15453 toString: function() {
15454 return ("DragDrop " + this.id);
15462 * Ext JS Library 1.1.1
15463 * Copyright(c) 2006-2007, Ext JS, LLC.
15465 * Originally Released Under LGPL - original licence link has changed is not relivant.
15468 * <script type="text/javascript">
15473 * The drag and drop utility provides a framework for building drag and drop
15474 * applications. In addition to enabling drag and drop for specific elements,
15475 * the drag and drop elements are tracked by the manager class, and the
15476 * interactions between the various elements are tracked during the drag and
15477 * the implementing code is notified about these important moments.
15480 // Only load the library once. Rewriting the manager class would orphan
15481 // existing drag and drop instances.
15482 if (!Roo.dd.DragDropMgr) {
15485 * @class Roo.dd.DragDropMgr
15486 * DragDropMgr is a singleton that tracks the element interaction for
15487 * all DragDrop items in the window. Generally, you will not call
15488 * this class directly, but it does have helper methods that could
15489 * be useful in your DragDrop implementations.
15492 Roo.dd.DragDropMgr = function() {
15494 var Event = Roo.EventManager;
15499 * Two dimensional Array of registered DragDrop objects. The first
15500 * dimension is the DragDrop item group, the second the DragDrop
15503 * @type {string: string}
15510 * Array of element ids defined as drag handles. Used to determine
15511 * if the element that generated the mousedown event is actually the
15512 * handle and not the html element itself.
15513 * @property handleIds
15514 * @type {string: string}
15521 * the DragDrop object that is currently being dragged
15522 * @property dragCurrent
15530 * the DragDrop object(s) that are being hovered over
15531 * @property dragOvers
15539 * the X distance between the cursor and the object being dragged
15548 * the Y distance between the cursor and the object being dragged
15557 * Flag to determine if we should prevent the default behavior of the
15558 * events we define. By default this is true, but this can be set to
15559 * false if you need the default behavior (not recommended)
15560 * @property preventDefault
15564 preventDefault: true,
15567 * Flag to determine if we should stop the propagation of the events
15568 * we generate. This is true by default but you may want to set it to
15569 * false if the html element contains other features that require the
15571 * @property stopPropagation
15575 stopPropagation: true,
15578 * Internal flag that is set to true when drag and drop has been
15580 * @property initialized
15587 * All drag and drop can be disabled.
15595 * Called the first time an element is registered.
15601 this.initialized = true;
15605 * In point mode, drag and drop interaction is defined by the
15606 * location of the cursor during the drag/drop
15614 * In intersect mode, drag and drop interactio nis defined by the
15615 * overlap of two or more drag and drop objects.
15616 * @property INTERSECT
15623 * The current drag and drop mode. Default: POINT
15631 * Runs method on all drag and drop objects
15632 * @method _execOnAll
15636 _execOnAll: function(sMethod, args) {
15637 for (var i in this.ids) {
15638 for (var j in this.ids[i]) {
15639 var oDD = this.ids[i][j];
15640 if (! this.isTypeOfDD(oDD)) {
15643 oDD[sMethod].apply(oDD, args);
15649 * Drag and drop initialization. Sets up the global event handlers
15654 _onLoad: function() {
15659 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15660 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15661 Event.on(window, "unload", this._onUnload, this, true);
15662 Event.on(window, "resize", this._onResize, this, true);
15663 // Event.on(window, "mouseout", this._test);
15668 * Reset constraints on all drag and drop objs
15669 * @method _onResize
15673 _onResize: function(e) {
15674 this._execOnAll("resetConstraints", []);
15678 * Lock all drag and drop functionality
15682 lock: function() { this.locked = true; },
15685 * Unlock all drag and drop functionality
15689 unlock: function() { this.locked = false; },
15692 * Is drag and drop locked?
15694 * @return {boolean} True if drag and drop is locked, false otherwise.
15697 isLocked: function() { return this.locked; },
15700 * Location cache that is set for all drag drop objects when a drag is
15701 * initiated, cleared when the drag is finished.
15702 * @property locationCache
15709 * Set useCache to false if you want to force object the lookup of each
15710 * drag and drop linked element constantly during a drag.
15711 * @property useCache
15718 * The number of pixels that the mouse needs to move after the
15719 * mousedown before the drag is initiated. Default=3;
15720 * @property clickPixelThresh
15724 clickPixelThresh: 3,
15727 * The number of milliseconds after the mousedown event to initiate the
15728 * drag if we don't get a mouseup event. Default=1000
15729 * @property clickTimeThresh
15733 clickTimeThresh: 350,
15736 * Flag that indicates that either the drag pixel threshold or the
15737 * mousdown time threshold has been met
15738 * @property dragThreshMet
15743 dragThreshMet: false,
15746 * Timeout used for the click time threshold
15747 * @property clickTimeout
15752 clickTimeout: null,
15755 * The X position of the mousedown event stored for later use when a
15756 * drag threshold is met.
15765 * The Y position of the mousedown event stored for later use when a
15766 * drag threshold is met.
15775 * Each DragDrop instance must be registered with the DragDropMgr.
15776 * This is executed in DragDrop.init()
15777 * @method regDragDrop
15778 * @param {DragDrop} oDD the DragDrop object to register
15779 * @param {String} sGroup the name of the group this element belongs to
15782 regDragDrop: function(oDD, sGroup) {
15783 if (!this.initialized) { this.init(); }
15785 if (!this.ids[sGroup]) {
15786 this.ids[sGroup] = {};
15788 this.ids[sGroup][oDD.id] = oDD;
15792 * Removes the supplied dd instance from the supplied group. Executed
15793 * by DragDrop.removeFromGroup, so don't call this function directly.
15794 * @method removeDDFromGroup
15798 removeDDFromGroup: function(oDD, sGroup) {
15799 if (!this.ids[sGroup]) {
15800 this.ids[sGroup] = {};
15803 var obj = this.ids[sGroup];
15804 if (obj && obj[oDD.id]) {
15805 delete obj[oDD.id];
15810 * Unregisters a drag and drop item. This is executed in
15811 * DragDrop.unreg, use that method instead of calling this directly.
15816 _remove: function(oDD) {
15817 for (var g in oDD.groups) {
15818 if (g && this.ids[g][oDD.id]) {
15819 delete this.ids[g][oDD.id];
15822 delete this.handleIds[oDD.id];
15826 * Each DragDrop handle element must be registered. This is done
15827 * automatically when executing DragDrop.setHandleElId()
15828 * @method regHandle
15829 * @param {String} sDDId the DragDrop id this element is a handle for
15830 * @param {String} sHandleId the id of the element that is the drag
15834 regHandle: function(sDDId, sHandleId) {
15835 if (!this.handleIds[sDDId]) {
15836 this.handleIds[sDDId] = {};
15838 this.handleIds[sDDId][sHandleId] = sHandleId;
15842 * Utility function to determine if a given element has been
15843 * registered as a drag drop item.
15844 * @method isDragDrop
15845 * @param {String} id the element id to check
15846 * @return {boolean} true if this element is a DragDrop item,
15850 isDragDrop: function(id) {
15851 return ( this.getDDById(id) ) ? true : false;
15855 * Returns the drag and drop instances that are in all groups the
15856 * passed in instance belongs to.
15857 * @method getRelated
15858 * @param {DragDrop} p_oDD the obj to get related data for
15859 * @param {boolean} bTargetsOnly if true, only return targetable objs
15860 * @return {DragDrop[]} the related instances
15863 getRelated: function(p_oDD, bTargetsOnly) {
15865 for (var i in p_oDD.groups) {
15866 for (j in this.ids[i]) {
15867 var dd = this.ids[i][j];
15868 if (! this.isTypeOfDD(dd)) {
15871 if (!bTargetsOnly || dd.isTarget) {
15872 oDDs[oDDs.length] = dd;
15881 * Returns true if the specified dd target is a legal target for
15882 * the specifice drag obj
15883 * @method isLegalTarget
15884 * @param {DragDrop} the drag obj
15885 * @param {DragDrop} the target
15886 * @return {boolean} true if the target is a legal target for the
15890 isLegalTarget: function (oDD, oTargetDD) {
15891 var targets = this.getRelated(oDD, true);
15892 for (var i=0, len=targets.length;i<len;++i) {
15893 if (targets[i].id == oTargetDD.id) {
15902 * My goal is to be able to transparently determine if an object is
15903 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15904 * returns "object", oDD.constructor.toString() always returns
15905 * "DragDrop" and not the name of the subclass. So for now it just
15906 * evaluates a well-known variable in DragDrop.
15907 * @method isTypeOfDD
15908 * @param {Object} the object to evaluate
15909 * @return {boolean} true if typeof oDD = DragDrop
15912 isTypeOfDD: function (oDD) {
15913 return (oDD && oDD.__ygDragDrop);
15917 * Utility function to determine if a given element has been
15918 * registered as a drag drop handle for the given Drag Drop object.
15920 * @param {String} id the element id to check
15921 * @return {boolean} true if this element is a DragDrop handle, false
15925 isHandle: function(sDDId, sHandleId) {
15926 return ( this.handleIds[sDDId] &&
15927 this.handleIds[sDDId][sHandleId] );
15931 * Returns the DragDrop instance for a given id
15932 * @method getDDById
15933 * @param {String} id the id of the DragDrop object
15934 * @return {DragDrop} the drag drop object, null if it is not found
15937 getDDById: function(id) {
15938 for (var i in this.ids) {
15939 if (this.ids[i][id]) {
15940 return this.ids[i][id];
15947 * Fired after a registered DragDrop object gets the mousedown event.
15948 * Sets up the events required to track the object being dragged
15949 * @method handleMouseDown
15950 * @param {Event} e the event
15951 * @param oDD the DragDrop object being dragged
15955 handleMouseDown: function(e, oDD) {
15957 Roo.QuickTips.disable();
15959 this.currentTarget = e.getTarget();
15961 this.dragCurrent = oDD;
15963 var el = oDD.getEl();
15965 // track start position
15966 this.startX = e.getPageX();
15967 this.startY = e.getPageY();
15969 this.deltaX = this.startX - el.offsetLeft;
15970 this.deltaY = this.startY - el.offsetTop;
15972 this.dragThreshMet = false;
15974 this.clickTimeout = setTimeout(
15976 var DDM = Roo.dd.DDM;
15977 DDM.startDrag(DDM.startX, DDM.startY);
15979 this.clickTimeThresh );
15983 * Fired when either the drag pixel threshol or the mousedown hold
15984 * time threshold has been met.
15985 * @method startDrag
15986 * @param x {int} the X position of the original mousedown
15987 * @param y {int} the Y position of the original mousedown
15990 startDrag: function(x, y) {
15991 clearTimeout(this.clickTimeout);
15992 if (this.dragCurrent) {
15993 this.dragCurrent.b4StartDrag(x, y);
15994 this.dragCurrent.startDrag(x, y);
15996 this.dragThreshMet = true;
16000 * Internal function to handle the mouseup event. Will be invoked
16001 * from the context of the document.
16002 * @method handleMouseUp
16003 * @param {Event} e the event
16007 handleMouseUp: function(e) {
16010 Roo.QuickTips.enable();
16012 if (! this.dragCurrent) {
16016 clearTimeout(this.clickTimeout);
16018 if (this.dragThreshMet) {
16019 this.fireEvents(e, true);
16029 * Utility to stop event propagation and event default, if these
16030 * features are turned on.
16031 * @method stopEvent
16032 * @param {Event} e the event as returned by this.getEvent()
16035 stopEvent: function(e){
16036 if(this.stopPropagation) {
16037 e.stopPropagation();
16040 if (this.preventDefault) {
16041 e.preventDefault();
16046 * Internal function to clean up event handlers after the drag
16047 * operation is complete
16049 * @param {Event} e the event
16053 stopDrag: function(e) {
16054 // Fire the drag end event for the item that was dragged
16055 if (this.dragCurrent) {
16056 if (this.dragThreshMet) {
16057 this.dragCurrent.b4EndDrag(e);
16058 this.dragCurrent.endDrag(e);
16061 this.dragCurrent.onMouseUp(e);
16064 this.dragCurrent = null;
16065 this.dragOvers = {};
16069 * Internal function to handle the mousemove event. Will be invoked
16070 * from the context of the html element.
16072 * @TODO figure out what we can do about mouse events lost when the
16073 * user drags objects beyond the window boundary. Currently we can
16074 * detect this in internet explorer by verifying that the mouse is
16075 * down during the mousemove event. Firefox doesn't give us the
16076 * button state on the mousemove event.
16077 * @method handleMouseMove
16078 * @param {Event} e the event
16082 handleMouseMove: function(e) {
16083 if (! this.dragCurrent) {
16087 // var button = e.which || e.button;
16089 // check for IE mouseup outside of page boundary
16090 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16092 return this.handleMouseUp(e);
16095 if (!this.dragThreshMet) {
16096 var diffX = Math.abs(this.startX - e.getPageX());
16097 var diffY = Math.abs(this.startY - e.getPageY());
16098 if (diffX > this.clickPixelThresh ||
16099 diffY > this.clickPixelThresh) {
16100 this.startDrag(this.startX, this.startY);
16104 if (this.dragThreshMet) {
16105 this.dragCurrent.b4Drag(e);
16106 this.dragCurrent.onDrag(e);
16107 if(!this.dragCurrent.moveOnly){
16108 this.fireEvents(e, false);
16118 * Iterates over all of the DragDrop elements to find ones we are
16119 * hovering over or dropping on
16120 * @method fireEvents
16121 * @param {Event} e the event
16122 * @param {boolean} isDrop is this a drop op or a mouseover op?
16126 fireEvents: function(e, isDrop) {
16127 var dc = this.dragCurrent;
16129 // If the user did the mouse up outside of the window, we could
16130 // get here even though we have ended the drag.
16131 if (!dc || dc.isLocked()) {
16135 var pt = e.getPoint();
16137 // cache the previous dragOver array
16143 var enterEvts = [];
16145 // Check to see if the object(s) we were hovering over is no longer
16146 // being hovered over so we can fire the onDragOut event
16147 for (var i in this.dragOvers) {
16149 var ddo = this.dragOvers[i];
16151 if (! this.isTypeOfDD(ddo)) {
16155 if (! this.isOverTarget(pt, ddo, this.mode)) {
16156 outEvts.push( ddo );
16159 oldOvers[i] = true;
16160 delete this.dragOvers[i];
16163 for (var sGroup in dc.groups) {
16165 if ("string" != typeof sGroup) {
16169 for (i in this.ids[sGroup]) {
16170 var oDD = this.ids[sGroup][i];
16171 if (! this.isTypeOfDD(oDD)) {
16175 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16176 if (this.isOverTarget(pt, oDD, this.mode)) {
16177 // look for drop interactions
16179 dropEvts.push( oDD );
16180 // look for drag enter and drag over interactions
16183 // initial drag over: dragEnter fires
16184 if (!oldOvers[oDD.id]) {
16185 enterEvts.push( oDD );
16186 // subsequent drag overs: dragOver fires
16188 overEvts.push( oDD );
16191 this.dragOvers[oDD.id] = oDD;
16199 if (outEvts.length) {
16200 dc.b4DragOut(e, outEvts);
16201 dc.onDragOut(e, outEvts);
16204 if (enterEvts.length) {
16205 dc.onDragEnter(e, enterEvts);
16208 if (overEvts.length) {
16209 dc.b4DragOver(e, overEvts);
16210 dc.onDragOver(e, overEvts);
16213 if (dropEvts.length) {
16214 dc.b4DragDrop(e, dropEvts);
16215 dc.onDragDrop(e, dropEvts);
16219 // fire dragout events
16221 for (i=0, len=outEvts.length; i<len; ++i) {
16222 dc.b4DragOut(e, outEvts[i].id);
16223 dc.onDragOut(e, outEvts[i].id);
16226 // fire enter events
16227 for (i=0,len=enterEvts.length; i<len; ++i) {
16228 // dc.b4DragEnter(e, oDD.id);
16229 dc.onDragEnter(e, enterEvts[i].id);
16232 // fire over events
16233 for (i=0,len=overEvts.length; i<len; ++i) {
16234 dc.b4DragOver(e, overEvts[i].id);
16235 dc.onDragOver(e, overEvts[i].id);
16238 // fire drop events
16239 for (i=0, len=dropEvts.length; i<len; ++i) {
16240 dc.b4DragDrop(e, dropEvts[i].id);
16241 dc.onDragDrop(e, dropEvts[i].id);
16246 // notify about a drop that did not find a target
16247 if (isDrop && !dropEvts.length) {
16248 dc.onInvalidDrop(e);
16254 * Helper function for getting the best match from the list of drag
16255 * and drop objects returned by the drag and drop events when we are
16256 * in INTERSECT mode. It returns either the first object that the
16257 * cursor is over, or the object that has the greatest overlap with
16258 * the dragged element.
16259 * @method getBestMatch
16260 * @param {DragDrop[]} dds The array of drag and drop objects
16262 * @return {DragDrop} The best single match
16265 getBestMatch: function(dds) {
16267 // Return null if the input is not what we expect
16268 //if (!dds || !dds.length || dds.length == 0) {
16270 // If there is only one item, it wins
16271 //} else if (dds.length == 1) {
16273 var len = dds.length;
16278 // Loop through the targeted items
16279 for (var i=0; i<len; ++i) {
16281 // If the cursor is over the object, it wins. If the
16282 // cursor is over multiple matches, the first one we come
16284 if (dd.cursorIsOver) {
16287 // Otherwise the object with the most overlap wins
16290 winner.overlap.getArea() < dd.overlap.getArea()) {
16301 * Refreshes the cache of the top-left and bottom-right points of the
16302 * drag and drop objects in the specified group(s). This is in the
16303 * format that is stored in the drag and drop instance, so typical
16306 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16310 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16312 * @TODO this really should be an indexed array. Alternatively this
16313 * method could accept both.
16314 * @method refreshCache
16315 * @param {Object} groups an associative array of groups to refresh
16318 refreshCache: function(groups) {
16319 for (var sGroup in groups) {
16320 if ("string" != typeof sGroup) {
16323 for (var i in this.ids[sGroup]) {
16324 var oDD = this.ids[sGroup][i];
16326 if (this.isTypeOfDD(oDD)) {
16327 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16328 var loc = this.getLocation(oDD);
16330 this.locationCache[oDD.id] = loc;
16332 delete this.locationCache[oDD.id];
16333 // this will unregister the drag and drop object if
16334 // the element is not in a usable state
16343 * This checks to make sure an element exists and is in the DOM. The
16344 * main purpose is to handle cases where innerHTML is used to remove
16345 * drag and drop objects from the DOM. IE provides an 'unspecified
16346 * error' when trying to access the offsetParent of such an element
16348 * @param {HTMLElement} el the element to check
16349 * @return {boolean} true if the element looks usable
16352 verifyEl: function(el) {
16357 parent = el.offsetParent;
16360 parent = el.offsetParent;
16371 * Returns a Region object containing the drag and drop element's position
16372 * and size, including the padding configured for it
16373 * @method getLocation
16374 * @param {DragDrop} oDD the drag and drop object to get the
16376 * @return {Roo.lib.Region} a Region object representing the total area
16377 * the element occupies, including any padding
16378 * the instance is configured for.
16381 getLocation: function(oDD) {
16382 if (! this.isTypeOfDD(oDD)) {
16386 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16389 pos= Roo.lib.Dom.getXY(el);
16397 x2 = x1 + el.offsetWidth;
16399 y2 = y1 + el.offsetHeight;
16401 t = y1 - oDD.padding[0];
16402 r = x2 + oDD.padding[1];
16403 b = y2 + oDD.padding[2];
16404 l = x1 - oDD.padding[3];
16406 return new Roo.lib.Region( t, r, b, l );
16410 * Checks the cursor location to see if it over the target
16411 * @method isOverTarget
16412 * @param {Roo.lib.Point} pt The point to evaluate
16413 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16414 * @return {boolean} true if the mouse is over the target
16418 isOverTarget: function(pt, oTarget, intersect) {
16419 // use cache if available
16420 var loc = this.locationCache[oTarget.id];
16421 if (!loc || !this.useCache) {
16422 loc = this.getLocation(oTarget);
16423 this.locationCache[oTarget.id] = loc;
16431 oTarget.cursorIsOver = loc.contains( pt );
16433 // DragDrop is using this as a sanity check for the initial mousedown
16434 // in this case we are done. In POINT mode, if the drag obj has no
16435 // contraints, we are also done. Otherwise we need to evaluate the
16436 // location of the target as related to the actual location of the
16437 // dragged element.
16438 var dc = this.dragCurrent;
16439 if (!dc || !dc.getTargetCoord ||
16440 (!intersect && !dc.constrainX && !dc.constrainY)) {
16441 return oTarget.cursorIsOver;
16444 oTarget.overlap = null;
16446 // Get the current location of the drag element, this is the
16447 // location of the mouse event less the delta that represents
16448 // where the original mousedown happened on the element. We
16449 // need to consider constraints and ticks as well.
16450 var pos = dc.getTargetCoord(pt.x, pt.y);
16452 var el = dc.getDragEl();
16453 var curRegion = new Roo.lib.Region( pos.y,
16454 pos.x + el.offsetWidth,
16455 pos.y + el.offsetHeight,
16458 var overlap = curRegion.intersect(loc);
16461 oTarget.overlap = overlap;
16462 return (intersect) ? true : oTarget.cursorIsOver;
16469 * unload event handler
16470 * @method _onUnload
16474 _onUnload: function(e, me) {
16475 Roo.dd.DragDropMgr.unregAll();
16479 * Cleans up the drag and drop events and objects.
16484 unregAll: function() {
16486 if (this.dragCurrent) {
16488 this.dragCurrent = null;
16491 this._execOnAll("unreg", []);
16493 for (i in this.elementCache) {
16494 delete this.elementCache[i];
16497 this.elementCache = {};
16502 * A cache of DOM elements
16503 * @property elementCache
16510 * Get the wrapper for the DOM element specified
16511 * @method getElWrapper
16512 * @param {String} id the id of the element to get
16513 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16515 * @deprecated This wrapper isn't that useful
16518 getElWrapper: function(id) {
16519 var oWrapper = this.elementCache[id];
16520 if (!oWrapper || !oWrapper.el) {
16521 oWrapper = this.elementCache[id] =
16522 new this.ElementWrapper(Roo.getDom(id));
16528 * Returns the actual DOM element
16529 * @method getElement
16530 * @param {String} id the id of the elment to get
16531 * @return {Object} The element
16532 * @deprecated use Roo.getDom instead
16535 getElement: function(id) {
16536 return Roo.getDom(id);
16540 * Returns the style property for the DOM element (i.e.,
16541 * document.getElById(id).style)
16543 * @param {String} id the id of the elment to get
16544 * @return {Object} The style property of the element
16545 * @deprecated use Roo.getDom instead
16548 getCss: function(id) {
16549 var el = Roo.getDom(id);
16550 return (el) ? el.style : null;
16554 * Inner class for cached elements
16555 * @class DragDropMgr.ElementWrapper
16560 ElementWrapper: function(el) {
16565 this.el = el || null;
16570 this.id = this.el && el.id;
16572 * A reference to the style property
16575 this.css = this.el && el.style;
16579 * Returns the X position of an html element
16581 * @param el the element for which to get the position
16582 * @return {int} the X coordinate
16584 * @deprecated use Roo.lib.Dom.getX instead
16587 getPosX: function(el) {
16588 return Roo.lib.Dom.getX(el);
16592 * Returns the Y position of an html element
16594 * @param el the element for which to get the position
16595 * @return {int} the Y coordinate
16596 * @deprecated use Roo.lib.Dom.getY instead
16599 getPosY: function(el) {
16600 return Roo.lib.Dom.getY(el);
16604 * Swap two nodes. In IE, we use the native method, for others we
16605 * emulate the IE behavior
16607 * @param n1 the first node to swap
16608 * @param n2 the other node to swap
16611 swapNode: function(n1, n2) {
16615 var p = n2.parentNode;
16616 var s = n2.nextSibling;
16619 p.insertBefore(n1, n2);
16620 } else if (n2 == n1.nextSibling) {
16621 p.insertBefore(n2, n1);
16623 n1.parentNode.replaceChild(n2, n1);
16624 p.insertBefore(n1, s);
16630 * Returns the current scroll position
16631 * @method getScroll
16635 getScroll: function () {
16636 var t, l, dde=document.documentElement, db=document.body;
16637 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16639 l = dde.scrollLeft;
16646 return { top: t, left: l };
16650 * Returns the specified element style property
16652 * @param {HTMLElement} el the element
16653 * @param {string} styleProp the style property
16654 * @return {string} The value of the style property
16655 * @deprecated use Roo.lib.Dom.getStyle
16658 getStyle: function(el, styleProp) {
16659 return Roo.fly(el).getStyle(styleProp);
16663 * Gets the scrollTop
16664 * @method getScrollTop
16665 * @return {int} the document's scrollTop
16668 getScrollTop: function () { return this.getScroll().top; },
16671 * Gets the scrollLeft
16672 * @method getScrollLeft
16673 * @return {int} the document's scrollTop
16676 getScrollLeft: function () { return this.getScroll().left; },
16679 * Sets the x/y position of an element to the location of the
16682 * @param {HTMLElement} moveEl The element to move
16683 * @param {HTMLElement} targetEl The position reference element
16686 moveToEl: function (moveEl, targetEl) {
16687 var aCoord = Roo.lib.Dom.getXY(targetEl);
16688 Roo.lib.Dom.setXY(moveEl, aCoord);
16692 * Numeric array sort function
16693 * @method numericSort
16696 numericSort: function(a, b) { return (a - b); },
16700 * @property _timeoutCount
16707 * Trying to make the load order less important. Without this we get
16708 * an error if this file is loaded before the Event Utility.
16709 * @method _addListeners
16713 _addListeners: function() {
16714 var DDM = Roo.dd.DDM;
16715 if ( Roo.lib.Event && document ) {
16718 if (DDM._timeoutCount > 2000) {
16720 setTimeout(DDM._addListeners, 10);
16721 if (document && document.body) {
16722 DDM._timeoutCount += 1;
16729 * Recursively searches the immediate parent and all child nodes for
16730 * the handle element in order to determine wheter or not it was
16732 * @method handleWasClicked
16733 * @param node the html element to inspect
16736 handleWasClicked: function(node, id) {
16737 if (this.isHandle(id, node.id)) {
16740 // check to see if this is a text node child of the one we want
16741 var p = node.parentNode;
16744 if (this.isHandle(id, p.id)) {
16759 // shorter alias, save a few bytes
16760 Roo.dd.DDM = Roo.dd.DragDropMgr;
16761 Roo.dd.DDM._addListeners();
16765 * Ext JS Library 1.1.1
16766 * Copyright(c) 2006-2007, Ext JS, LLC.
16768 * Originally Released Under LGPL - original licence link has changed is not relivant.
16771 * <script type="text/javascript">
16776 * A DragDrop implementation where the linked element follows the
16777 * mouse cursor during a drag.
16778 * @extends Roo.dd.DragDrop
16780 * @param {String} id the id of the linked element
16781 * @param {String} sGroup the group of related DragDrop items
16782 * @param {object} config an object containing configurable attributes
16783 * Valid properties for DD:
16786 Roo.dd.DD = function(id, sGroup, config) {
16788 this.init(id, sGroup, config);
16792 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16795 * When set to true, the utility automatically tries to scroll the browser
16796 * window wehn a drag and drop element is dragged near the viewport boundary.
16797 * Defaults to true.
16804 * Sets the pointer offset to the distance between the linked element's top
16805 * left corner and the location the element was clicked
16806 * @method autoOffset
16807 * @param {int} iPageX the X coordinate of the click
16808 * @param {int} iPageY the Y coordinate of the click
16810 autoOffset: function(iPageX, iPageY) {
16811 var x = iPageX - this.startPageX;
16812 var y = iPageY - this.startPageY;
16813 this.setDelta(x, y);
16817 * Sets the pointer offset. You can call this directly to force the
16818 * offset to be in a particular location (e.g., pass in 0,0 to set it
16819 * to the center of the object)
16821 * @param {int} iDeltaX the distance from the left
16822 * @param {int} iDeltaY the distance from the top
16824 setDelta: function(iDeltaX, iDeltaY) {
16825 this.deltaX = iDeltaX;
16826 this.deltaY = iDeltaY;
16830 * Sets the drag element to the location of the mousedown or click event,
16831 * maintaining the cursor location relative to the location on the element
16832 * that was clicked. Override this if you want to place the element in a
16833 * location other than where the cursor is.
16834 * @method setDragElPos
16835 * @param {int} iPageX the X coordinate of the mousedown or drag event
16836 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16838 setDragElPos: function(iPageX, iPageY) {
16839 // the first time we do this, we are going to check to make sure
16840 // the element has css positioning
16842 var el = this.getDragEl();
16843 this.alignElWithMouse(el, iPageX, iPageY);
16847 * Sets the element to the location of the mousedown or click event,
16848 * maintaining the cursor location relative to the location on the element
16849 * that was clicked. Override this if you want to place the element in a
16850 * location other than where the cursor is.
16851 * @method alignElWithMouse
16852 * @param {HTMLElement} el the element to move
16853 * @param {int} iPageX the X coordinate of the mousedown or drag event
16854 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16856 alignElWithMouse: function(el, iPageX, iPageY) {
16857 var oCoord = this.getTargetCoord(iPageX, iPageY);
16858 var fly = el.dom ? el : Roo.fly(el);
16859 if (!this.deltaSetXY) {
16860 var aCoord = [oCoord.x, oCoord.y];
16862 var newLeft = fly.getLeft(true);
16863 var newTop = fly.getTop(true);
16864 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16866 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16869 this.cachePosition(oCoord.x, oCoord.y);
16870 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16875 * Saves the most recent position so that we can reset the constraints and
16876 * tick marks on-demand. We need to know this so that we can calculate the
16877 * number of pixels the element is offset from its original position.
16878 * @method cachePosition
16879 * @param iPageX the current x position (optional, this just makes it so we
16880 * don't have to look it up again)
16881 * @param iPageY the current y position (optional, this just makes it so we
16882 * don't have to look it up again)
16884 cachePosition: function(iPageX, iPageY) {
16886 this.lastPageX = iPageX;
16887 this.lastPageY = iPageY;
16889 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16890 this.lastPageX = aCoord[0];
16891 this.lastPageY = aCoord[1];
16896 * Auto-scroll the window if the dragged object has been moved beyond the
16897 * visible window boundary.
16898 * @method autoScroll
16899 * @param {int} x the drag element's x position
16900 * @param {int} y the drag element's y position
16901 * @param {int} h the height of the drag element
16902 * @param {int} w the width of the drag element
16905 autoScroll: function(x, y, h, w) {
16908 // The client height
16909 var clientH = Roo.lib.Dom.getViewWidth();
16911 // The client width
16912 var clientW = Roo.lib.Dom.getViewHeight();
16914 // The amt scrolled down
16915 var st = this.DDM.getScrollTop();
16917 // The amt scrolled right
16918 var sl = this.DDM.getScrollLeft();
16920 // Location of the bottom of the element
16923 // Location of the right of the element
16926 // The distance from the cursor to the bottom of the visible area,
16927 // adjusted so that we don't scroll if the cursor is beyond the
16928 // element drag constraints
16929 var toBot = (clientH + st - y - this.deltaY);
16931 // The distance from the cursor to the right of the visible area
16932 var toRight = (clientW + sl - x - this.deltaX);
16935 // How close to the edge the cursor must be before we scroll
16936 // var thresh = (document.all) ? 100 : 40;
16939 // How many pixels to scroll per autoscroll op. This helps to reduce
16940 // clunky scrolling. IE is more sensitive about this ... it needs this
16941 // value to be higher.
16942 var scrAmt = (document.all) ? 80 : 30;
16944 // Scroll down if we are near the bottom of the visible page and the
16945 // obj extends below the crease
16946 if ( bot > clientH && toBot < thresh ) {
16947 window.scrollTo(sl, st + scrAmt);
16950 // Scroll up if the window is scrolled down and the top of the object
16951 // goes above the top border
16952 if ( y < st && st > 0 && y - st < thresh ) {
16953 window.scrollTo(sl, st - scrAmt);
16956 // Scroll right if the obj is beyond the right border and the cursor is
16957 // near the border.
16958 if ( right > clientW && toRight < thresh ) {
16959 window.scrollTo(sl + scrAmt, st);
16962 // Scroll left if the window has been scrolled to the right and the obj
16963 // extends past the left border
16964 if ( x < sl && sl > 0 && x - sl < thresh ) {
16965 window.scrollTo(sl - scrAmt, st);
16971 * Finds the location the element should be placed if we want to move
16972 * it to where the mouse location less the click offset would place us.
16973 * @method getTargetCoord
16974 * @param {int} iPageX the X coordinate of the click
16975 * @param {int} iPageY the Y coordinate of the click
16976 * @return an object that contains the coordinates (Object.x and Object.y)
16979 getTargetCoord: function(iPageX, iPageY) {
16982 var x = iPageX - this.deltaX;
16983 var y = iPageY - this.deltaY;
16985 if (this.constrainX) {
16986 if (x < this.minX) { x = this.minX; }
16987 if (x > this.maxX) { x = this.maxX; }
16990 if (this.constrainY) {
16991 if (y < this.minY) { y = this.minY; }
16992 if (y > this.maxY) { y = this.maxY; }
16995 x = this.getTick(x, this.xTicks);
16996 y = this.getTick(y, this.yTicks);
17003 * Sets up config options specific to this class. Overrides
17004 * Roo.dd.DragDrop, but all versions of this method through the
17005 * inheritance chain are called
17007 applyConfig: function() {
17008 Roo.dd.DD.superclass.applyConfig.call(this);
17009 this.scroll = (this.config.scroll !== false);
17013 * Event that fires prior to the onMouseDown event. Overrides
17016 b4MouseDown: function(e) {
17017 // this.resetConstraints();
17018 this.autoOffset(e.getPageX(),
17023 * Event that fires prior to the onDrag event. Overrides
17026 b4Drag: function(e) {
17027 this.setDragElPos(e.getPageX(),
17031 toString: function() {
17032 return ("DD " + this.id);
17035 //////////////////////////////////////////////////////////////////////////
17036 // Debugging ygDragDrop events that can be overridden
17037 //////////////////////////////////////////////////////////////////////////
17039 startDrag: function(x, y) {
17042 onDrag: function(e) {
17045 onDragEnter: function(e, id) {
17048 onDragOver: function(e, id) {
17051 onDragOut: function(e, id) {
17054 onDragDrop: function(e, id) {
17057 endDrag: function(e) {
17064 * Ext JS Library 1.1.1
17065 * Copyright(c) 2006-2007, Ext JS, LLC.
17067 * Originally Released Under LGPL - original licence link has changed is not relivant.
17070 * <script type="text/javascript">
17074 * @class Roo.dd.DDProxy
17075 * A DragDrop implementation that inserts an empty, bordered div into
17076 * the document that follows the cursor during drag operations. At the time of
17077 * the click, the frame div is resized to the dimensions of the linked html
17078 * element, and moved to the exact location of the linked element.
17080 * References to the "frame" element refer to the single proxy element that
17081 * was created to be dragged in place of all DDProxy elements on the
17084 * @extends Roo.dd.DD
17086 * @param {String} id the id of the linked html element
17087 * @param {String} sGroup the group of related DragDrop objects
17088 * @param {object} config an object containing configurable attributes
17089 * Valid properties for DDProxy in addition to those in DragDrop:
17090 * resizeFrame, centerFrame, dragElId
17092 Roo.dd.DDProxy = function(id, sGroup, config) {
17094 this.init(id, sGroup, config);
17100 * The default drag frame div id
17101 * @property Roo.dd.DDProxy.dragElId
17105 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17107 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17110 * By default we resize the drag frame to be the same size as the element
17111 * we want to drag (this is to get the frame effect). We can turn it off
17112 * if we want a different behavior.
17113 * @property resizeFrame
17119 * By default the frame is positioned exactly where the drag element is, so
17120 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17121 * you do not have constraints on the obj is to have the drag frame centered
17122 * around the cursor. Set centerFrame to true for this effect.
17123 * @property centerFrame
17126 centerFrame: false,
17129 * Creates the proxy element if it does not yet exist
17130 * @method createFrame
17132 createFrame: function() {
17134 var body = document.body;
17136 if (!body || !body.firstChild) {
17137 setTimeout( function() { self.createFrame(); }, 50 );
17141 var div = this.getDragEl();
17144 div = document.createElement("div");
17145 div.id = this.dragElId;
17148 s.position = "absolute";
17149 s.visibility = "hidden";
17151 s.border = "2px solid #aaa";
17154 // appendChild can blow up IE if invoked prior to the window load event
17155 // while rendering a table. It is possible there are other scenarios
17156 // that would cause this to happen as well.
17157 body.insertBefore(div, body.firstChild);
17162 * Initialization for the drag frame element. Must be called in the
17163 * constructor of all subclasses
17164 * @method initFrame
17166 initFrame: function() {
17167 this.createFrame();
17170 applyConfig: function() {
17171 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17173 this.resizeFrame = (this.config.resizeFrame !== false);
17174 this.centerFrame = (this.config.centerFrame);
17175 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17179 * Resizes the drag frame to the dimensions of the clicked object, positions
17180 * it over the object, and finally displays it
17181 * @method showFrame
17182 * @param {int} iPageX X click position
17183 * @param {int} iPageY Y click position
17186 showFrame: function(iPageX, iPageY) {
17187 var el = this.getEl();
17188 var dragEl = this.getDragEl();
17189 var s = dragEl.style;
17191 this._resizeProxy();
17193 if (this.centerFrame) {
17194 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17195 Math.round(parseInt(s.height, 10)/2) );
17198 this.setDragElPos(iPageX, iPageY);
17200 Roo.fly(dragEl).show();
17204 * The proxy is automatically resized to the dimensions of the linked
17205 * element when a drag is initiated, unless resizeFrame is set to false
17206 * @method _resizeProxy
17209 _resizeProxy: function() {
17210 if (this.resizeFrame) {
17211 var el = this.getEl();
17212 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17216 // overrides Roo.dd.DragDrop
17217 b4MouseDown: function(e) {
17218 var x = e.getPageX();
17219 var y = e.getPageY();
17220 this.autoOffset(x, y);
17221 this.setDragElPos(x, y);
17224 // overrides Roo.dd.DragDrop
17225 b4StartDrag: function(x, y) {
17226 // show the drag frame
17227 this.showFrame(x, y);
17230 // overrides Roo.dd.DragDrop
17231 b4EndDrag: function(e) {
17232 Roo.fly(this.getDragEl()).hide();
17235 // overrides Roo.dd.DragDrop
17236 // By default we try to move the element to the last location of the frame.
17237 // This is so that the default behavior mirrors that of Roo.dd.DD.
17238 endDrag: function(e) {
17240 var lel = this.getEl();
17241 var del = this.getDragEl();
17243 // Show the drag frame briefly so we can get its position
17244 del.style.visibility = "";
17247 // Hide the linked element before the move to get around a Safari
17249 lel.style.visibility = "hidden";
17250 Roo.dd.DDM.moveToEl(lel, del);
17251 del.style.visibility = "hidden";
17252 lel.style.visibility = "";
17257 beforeMove : function(){
17261 afterDrag : function(){
17265 toString: function() {
17266 return ("DDProxy " + this.id);
17272 * Ext JS Library 1.1.1
17273 * Copyright(c) 2006-2007, Ext JS, LLC.
17275 * Originally Released Under LGPL - original licence link has changed is not relivant.
17278 * <script type="text/javascript">
17282 * @class Roo.dd.DDTarget
17283 * A DragDrop implementation that does not move, but can be a drop
17284 * target. You would get the same result by simply omitting implementation
17285 * for the event callbacks, but this way we reduce the processing cost of the
17286 * event listener and the callbacks.
17287 * @extends Roo.dd.DragDrop
17289 * @param {String} id the id of the element that is a drop target
17290 * @param {String} sGroup the group of related DragDrop objects
17291 * @param {object} config an object containing configurable attributes
17292 * Valid properties for DDTarget in addition to those in
17296 Roo.dd.DDTarget = function(id, sGroup, config) {
17298 this.initTarget(id, sGroup, config);
17302 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17303 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17304 toString: function() {
17305 return ("DDTarget " + this.id);
17310 * Ext JS Library 1.1.1
17311 * Copyright(c) 2006-2007, Ext JS, LLC.
17313 * Originally Released Under LGPL - original licence link has changed is not relivant.
17316 * <script type="text/javascript">
17321 * @class Roo.dd.ScrollManager
17322 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17323 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17326 Roo.dd.ScrollManager = function(){
17327 var ddm = Roo.dd.DragDropMgr;
17332 var onStop = function(e){
17337 var triggerRefresh = function(){
17338 if(ddm.dragCurrent){
17339 ddm.refreshCache(ddm.dragCurrent.groups);
17343 var doScroll = function(){
17344 if(ddm.dragCurrent){
17345 var dds = Roo.dd.ScrollManager;
17347 if(proc.el.scroll(proc.dir, dds.increment)){
17351 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17356 var clearProc = function(){
17358 clearInterval(proc.id);
17365 var startProc = function(el, dir){
17369 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17372 var onFire = function(e, isDrop){
17373 if(isDrop || !ddm.dragCurrent){ return; }
17374 var dds = Roo.dd.ScrollManager;
17375 if(!dragEl || dragEl != ddm.dragCurrent){
17376 dragEl = ddm.dragCurrent;
17377 // refresh regions on drag start
17378 dds.refreshCache();
17381 var xy = Roo.lib.Event.getXY(e);
17382 var pt = new Roo.lib.Point(xy[0], xy[1]);
17383 for(var id in els){
17384 var el = els[id], r = el._region;
17385 if(r && r.contains(pt) && el.isScrollable()){
17386 if(r.bottom - pt.y <= dds.thresh){
17388 startProc(el, "down");
17391 }else if(r.right - pt.x <= dds.thresh){
17393 startProc(el, "left");
17396 }else if(pt.y - r.top <= dds.thresh){
17398 startProc(el, "up");
17401 }else if(pt.x - r.left <= dds.thresh){
17403 startProc(el, "right");
17412 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17413 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17417 * Registers new overflow element(s) to auto scroll
17418 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17420 register : function(el){
17421 if(el instanceof Array){
17422 for(var i = 0, len = el.length; i < len; i++) {
17423 this.register(el[i]);
17432 * Unregisters overflow element(s) so they are no longer scrolled
17433 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17435 unregister : function(el){
17436 if(el instanceof Array){
17437 for(var i = 0, len = el.length; i < len; i++) {
17438 this.unregister(el[i]);
17447 * The number of pixels from the edge of a container the pointer needs to be to
17448 * trigger scrolling (defaults to 25)
17454 * The number of pixels to scroll in each scroll increment (defaults to 50)
17460 * The frequency of scrolls in milliseconds (defaults to 500)
17466 * True to animate the scroll (defaults to true)
17472 * The animation duration in seconds -
17473 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17479 * Manually trigger a cache refresh.
17481 refreshCache : function(){
17482 for(var id in els){
17483 if(typeof els[id] == 'object'){ // for people extending the object prototype
17484 els[id]._region = els[id].getRegion();
17491 * Ext JS Library 1.1.1
17492 * Copyright(c) 2006-2007, Ext JS, LLC.
17494 * Originally Released Under LGPL - original licence link has changed is not relivant.
17497 * <script type="text/javascript">
17502 * @class Roo.dd.Registry
17503 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17504 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17507 Roo.dd.Registry = function(){
17510 var autoIdSeed = 0;
17512 var getId = function(el, autogen){
17513 if(typeof el == "string"){
17517 if(!id && autogen !== false){
17518 id = "roodd-" + (++autoIdSeed);
17526 * Register a drag drop element
17527 * @param {String|HTMLElement} element The id or DOM node to register
17528 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17529 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17530 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17531 * populated in the data object (if applicable):
17533 Value Description<br />
17534 --------- ------------------------------------------<br />
17535 handles Array of DOM nodes that trigger dragging<br />
17536 for the element being registered<br />
17537 isHandle True if the element passed in triggers<br />
17538 dragging itself, else false
17541 register : function(el, data){
17543 if(typeof el == "string"){
17544 el = document.getElementById(el);
17547 elements[getId(el)] = data;
17548 if(data.isHandle !== false){
17549 handles[data.ddel.id] = data;
17552 var hs = data.handles;
17553 for(var i = 0, len = hs.length; i < len; i++){
17554 handles[getId(hs[i])] = data;
17560 * Unregister a drag drop element
17561 * @param {String|HTMLElement} element The id or DOM node to unregister
17563 unregister : function(el){
17564 var id = getId(el, false);
17565 var data = elements[id];
17567 delete elements[id];
17569 var hs = data.handles;
17570 for(var i = 0, len = hs.length; i < len; i++){
17571 delete handles[getId(hs[i], false)];
17578 * Returns the handle registered for a DOM Node by id
17579 * @param {String|HTMLElement} id The DOM node or id to look up
17580 * @return {Object} handle The custom handle data
17582 getHandle : function(id){
17583 if(typeof id != "string"){ // must be element?
17586 return handles[id];
17590 * Returns the handle that is registered for the DOM node that is the target of the event
17591 * @param {Event} e The event
17592 * @return {Object} handle The custom handle data
17594 getHandleFromEvent : function(e){
17595 var t = Roo.lib.Event.getTarget(e);
17596 return t ? handles[t.id] : null;
17600 * Returns a custom data object that is registered for a DOM node by id
17601 * @param {String|HTMLElement} id The DOM node or id to look up
17602 * @return {Object} data The custom data
17604 getTarget : function(id){
17605 if(typeof id != "string"){ // must be element?
17608 return elements[id];
17612 * Returns a custom data object that is registered for the DOM node that is the target of the event
17613 * @param {Event} e The event
17614 * @return {Object} data The custom data
17616 getTargetFromEvent : function(e){
17617 var t = Roo.lib.Event.getTarget(e);
17618 return t ? elements[t.id] || handles[t.id] : null;
17623 * Ext JS Library 1.1.1
17624 * Copyright(c) 2006-2007, Ext JS, LLC.
17626 * Originally Released Under LGPL - original licence link has changed is not relivant.
17629 * <script type="text/javascript">
17634 * @class Roo.dd.StatusProxy
17635 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17636 * default drag proxy used by all Roo.dd components.
17638 * @param {Object} config
17640 Roo.dd.StatusProxy = function(config){
17641 Roo.apply(this, config);
17642 this.id = this.id || Roo.id();
17643 this.el = new Roo.Layer({
17645 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17646 {tag: "div", cls: "x-dd-drop-icon"},
17647 {tag: "div", cls: "x-dd-drag-ghost"}
17650 shadow: !config || config.shadow !== false
17652 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17653 this.dropStatus = this.dropNotAllowed;
17656 Roo.dd.StatusProxy.prototype = {
17658 * @cfg {String} dropAllowed
17659 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17661 dropAllowed : "x-dd-drop-ok",
17663 * @cfg {String} dropNotAllowed
17664 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17666 dropNotAllowed : "x-dd-drop-nodrop",
17669 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17670 * over the current target element.
17671 * @param {String} cssClass The css class for the new drop status indicator image
17673 setStatus : function(cssClass){
17674 cssClass = cssClass || this.dropNotAllowed;
17675 if(this.dropStatus != cssClass){
17676 this.el.replaceClass(this.dropStatus, cssClass);
17677 this.dropStatus = cssClass;
17682 * Resets the status indicator to the default dropNotAllowed value
17683 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17685 reset : function(clearGhost){
17686 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17687 this.dropStatus = this.dropNotAllowed;
17689 this.ghost.update("");
17694 * Updates the contents of the ghost element
17695 * @param {String} html The html that will replace the current innerHTML of the ghost element
17697 update : function(html){
17698 if(typeof html == "string"){
17699 this.ghost.update(html);
17701 this.ghost.update("");
17702 html.style.margin = "0";
17703 this.ghost.dom.appendChild(html);
17705 // ensure float = none set?? cant remember why though.
17706 var el = this.ghost.dom.firstChild;
17708 Roo.fly(el).setStyle('float', 'none');
17713 * Returns the underlying proxy {@link Roo.Layer}
17714 * @return {Roo.Layer} el
17716 getEl : function(){
17721 * Returns the ghost element
17722 * @return {Roo.Element} el
17724 getGhost : function(){
17730 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17732 hide : function(clear){
17740 * Stops the repair animation if it's currently running
17743 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17749 * Displays this proxy
17756 * Force the Layer to sync its shadow and shim positions to the element
17763 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17764 * invalid drop operation by the item being dragged.
17765 * @param {Array} xy The XY position of the element ([x, y])
17766 * @param {Function} callback The function to call after the repair is complete
17767 * @param {Object} scope The scope in which to execute the callback
17769 repair : function(xy, callback, scope){
17770 this.callback = callback;
17771 this.scope = scope;
17772 if(xy && this.animRepair !== false){
17773 this.el.addClass("x-dd-drag-repair");
17774 this.el.hideUnders(true);
17775 this.anim = this.el.shift({
17776 duration: this.repairDuration || .5,
17780 callback: this.afterRepair,
17784 this.afterRepair();
17789 afterRepair : function(){
17791 if(typeof this.callback == "function"){
17792 this.callback.call(this.scope || this);
17794 this.callback = null;
17799 * Ext JS Library 1.1.1
17800 * Copyright(c) 2006-2007, Ext JS, LLC.
17802 * Originally Released Under LGPL - original licence link has changed is not relivant.
17805 * <script type="text/javascript">
17809 * @class Roo.dd.DragSource
17810 * @extends Roo.dd.DDProxy
17811 * A simple class that provides the basic implementation needed to make any element draggable.
17813 * @param {String/HTMLElement/Element} el The container element
17814 * @param {Object} config
17816 Roo.dd.DragSource = function(el, config){
17817 this.el = Roo.get(el);
17818 this.dragData = {};
17820 Roo.apply(this, config);
17823 this.proxy = new Roo.dd.StatusProxy();
17826 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17827 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17829 this.dragging = false;
17832 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17834 * @cfg {String} dropAllowed
17835 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17837 dropAllowed : "x-dd-drop-ok",
17839 * @cfg {String} dropNotAllowed
17840 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17842 dropNotAllowed : "x-dd-drop-nodrop",
17845 * Returns the data object associated with this drag source
17846 * @return {Object} data An object containing arbitrary data
17848 getDragData : function(e){
17849 return this.dragData;
17853 onDragEnter : function(e, id){
17854 var target = Roo.dd.DragDropMgr.getDDById(id);
17855 this.cachedTarget = target;
17856 if(this.beforeDragEnter(target, e, id) !== false){
17857 if(target.isNotifyTarget){
17858 var status = target.notifyEnter(this, e, this.dragData);
17859 this.proxy.setStatus(status);
17861 this.proxy.setStatus(this.dropAllowed);
17864 if(this.afterDragEnter){
17866 * An empty function by default, but provided so that you can perform a custom action
17867 * when the dragged item enters the drop target by providing an implementation.
17868 * @param {Roo.dd.DragDrop} target The drop target
17869 * @param {Event} e The event object
17870 * @param {String} id The id of the dragged element
17871 * @method afterDragEnter
17873 this.afterDragEnter(target, e, id);
17879 * An empty function by default, but provided so that you can perform a custom action
17880 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17881 * @param {Roo.dd.DragDrop} target The drop target
17882 * @param {Event} e The event object
17883 * @param {String} id The id of the dragged element
17884 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17886 beforeDragEnter : function(target, e, id){
17891 alignElWithMouse: function() {
17892 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17897 onDragOver : function(e, id){
17898 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17899 if(this.beforeDragOver(target, e, id) !== false){
17900 if(target.isNotifyTarget){
17901 var status = target.notifyOver(this, e, this.dragData);
17902 this.proxy.setStatus(status);
17905 if(this.afterDragOver){
17907 * An empty function by default, but provided so that you can perform a custom action
17908 * while the dragged item is over the drop target by providing an implementation.
17909 * @param {Roo.dd.DragDrop} target The drop target
17910 * @param {Event} e The event object
17911 * @param {String} id The id of the dragged element
17912 * @method afterDragOver
17914 this.afterDragOver(target, e, id);
17920 * An empty function by default, but provided so that you can perform a custom action
17921 * while the dragged item is over the drop target and optionally cancel the onDragOver.
17922 * @param {Roo.dd.DragDrop} target The drop target
17923 * @param {Event} e The event object
17924 * @param {String} id The id of the dragged element
17925 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17927 beforeDragOver : function(target, e, id){
17932 onDragOut : function(e, id){
17933 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17934 if(this.beforeDragOut(target, e, id) !== false){
17935 if(target.isNotifyTarget){
17936 target.notifyOut(this, e, this.dragData);
17938 this.proxy.reset();
17939 if(this.afterDragOut){
17941 * An empty function by default, but provided so that you can perform a custom action
17942 * after the dragged item is dragged out of the target without dropping.
17943 * @param {Roo.dd.DragDrop} target The drop target
17944 * @param {Event} e The event object
17945 * @param {String} id The id of the dragged element
17946 * @method afterDragOut
17948 this.afterDragOut(target, e, id);
17951 this.cachedTarget = null;
17955 * An empty function by default, but provided so that you can perform a custom action before the dragged
17956 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
17957 * @param {Roo.dd.DragDrop} target The drop target
17958 * @param {Event} e The event object
17959 * @param {String} id The id of the dragged element
17960 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17962 beforeDragOut : function(target, e, id){
17967 onDragDrop : function(e, id){
17968 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17969 if(this.beforeDragDrop(target, e, id) !== false){
17970 if(target.isNotifyTarget){
17971 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
17972 this.onValidDrop(target, e, id);
17974 this.onInvalidDrop(target, e, id);
17977 this.onValidDrop(target, e, id);
17980 if(this.afterDragDrop){
17982 * An empty function by default, but provided so that you can perform a custom action
17983 * after a valid drag drop has occurred by providing an implementation.
17984 * @param {Roo.dd.DragDrop} target The drop target
17985 * @param {Event} e The event object
17986 * @param {String} id The id of the dropped element
17987 * @method afterDragDrop
17989 this.afterDragDrop(target, e, id);
17992 delete this.cachedTarget;
17996 * An empty function by default, but provided so that you can perform a custom action before the dragged
17997 * item is dropped onto the target and optionally cancel the onDragDrop.
17998 * @param {Roo.dd.DragDrop} target The drop target
17999 * @param {Event} e The event object
18000 * @param {String} id The id of the dragged element
18001 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18003 beforeDragDrop : function(target, e, id){
18008 onValidDrop : function(target, e, id){
18010 if(this.afterValidDrop){
18012 * An empty function by default, but provided so that you can perform a custom action
18013 * after a valid drop has occurred by providing an implementation.
18014 * @param {Object} target The target DD
18015 * @param {Event} e The event object
18016 * @param {String} id The id of the dropped element
18017 * @method afterInvalidDrop
18019 this.afterValidDrop(target, e, id);
18024 getRepairXY : function(e, data){
18025 return this.el.getXY();
18029 onInvalidDrop : function(target, e, id){
18030 this.beforeInvalidDrop(target, e, id);
18031 if(this.cachedTarget){
18032 if(this.cachedTarget.isNotifyTarget){
18033 this.cachedTarget.notifyOut(this, e, this.dragData);
18035 this.cacheTarget = null;
18037 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18039 if(this.afterInvalidDrop){
18041 * An empty function by default, but provided so that you can perform a custom action
18042 * after an invalid drop has occurred by providing an implementation.
18043 * @param {Event} e The event object
18044 * @param {String} id The id of the dropped element
18045 * @method afterInvalidDrop
18047 this.afterInvalidDrop(e, id);
18052 afterRepair : function(){
18054 this.el.highlight(this.hlColor || "c3daf9");
18056 this.dragging = false;
18060 * An empty function by default, but provided so that you can perform a custom action after an invalid
18061 * drop has occurred.
18062 * @param {Roo.dd.DragDrop} target The drop target
18063 * @param {Event} e The event object
18064 * @param {String} id The id of the dragged element
18065 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18067 beforeInvalidDrop : function(target, e, id){
18072 handleMouseDown : function(e){
18073 if(this.dragging) {
18076 var data = this.getDragData(e);
18077 if(data && this.onBeforeDrag(data, e) !== false){
18078 this.dragData = data;
18080 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18085 * An empty function by default, but provided so that you can perform a custom action before the initial
18086 * drag event begins and optionally cancel it.
18087 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18088 * @param {Event} e The event object
18089 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18091 onBeforeDrag : function(data, e){
18096 * An empty function by default, but provided so that you can perform a custom action once the initial
18097 * drag event has begun. The drag cannot be canceled from this function.
18098 * @param {Number} x The x position of the click on the dragged object
18099 * @param {Number} y The y position of the click on the dragged object
18101 onStartDrag : Roo.emptyFn,
18103 // private - YUI override
18104 startDrag : function(x, y){
18105 this.proxy.reset();
18106 this.dragging = true;
18107 this.proxy.update("");
18108 this.onInitDrag(x, y);
18113 onInitDrag : function(x, y){
18114 var clone = this.el.dom.cloneNode(true);
18115 clone.id = Roo.id(); // prevent duplicate ids
18116 this.proxy.update(clone);
18117 this.onStartDrag(x, y);
18122 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18123 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18125 getProxy : function(){
18130 * Hides the drag source's {@link Roo.dd.StatusProxy}
18132 hideProxy : function(){
18134 this.proxy.reset(true);
18135 this.dragging = false;
18139 triggerCacheRefresh : function(){
18140 Roo.dd.DDM.refreshCache(this.groups);
18143 // private - override to prevent hiding
18144 b4EndDrag: function(e) {
18147 // private - override to prevent moving
18148 endDrag : function(e){
18149 this.onEndDrag(this.dragData, e);
18153 onEndDrag : function(data, e){
18156 // private - pin to cursor
18157 autoOffset : function(x, y) {
18158 this.setDelta(-12, -20);
18162 * Ext JS Library 1.1.1
18163 * Copyright(c) 2006-2007, Ext JS, LLC.
18165 * Originally Released Under LGPL - original licence link has changed is not relivant.
18168 * <script type="text/javascript">
18173 * @class Roo.dd.DropTarget
18174 * @extends Roo.dd.DDTarget
18175 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18176 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18178 * @param {String/HTMLElement/Element} el The container element
18179 * @param {Object} config
18181 Roo.dd.DropTarget = function(el, config){
18182 this.el = Roo.get(el);
18184 Roo.apply(this, config);
18186 if(this.containerScroll){
18187 Roo.dd.ScrollManager.register(this.el);
18190 Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18195 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18197 * @cfg {String} overClass
18198 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18201 * @cfg {String} dropAllowed
18202 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18204 dropAllowed : "x-dd-drop-ok",
18206 * @cfg {String} dropNotAllowed
18207 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18209 dropNotAllowed : "x-dd-drop-nodrop",
18215 isNotifyTarget : true,
18218 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18219 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18220 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18221 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18222 * @param {Event} e The event
18223 * @param {Object} data An object containing arbitrary data supplied by the drag source
18224 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18225 * underlying {@link Roo.dd.StatusProxy} can be updated
18227 notifyEnter : function(dd, e, data){
18228 if(this.overClass){
18229 this.el.addClass(this.overClass);
18231 return this.dropAllowed;
18235 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18236 * This method will be called on every mouse movement while the drag source is over the drop target.
18237 * This default implementation simply returns the dropAllowed config value.
18238 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18239 * @param {Event} e The event
18240 * @param {Object} data An object containing arbitrary data supplied by the drag source
18241 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18242 * underlying {@link Roo.dd.StatusProxy} can be updated
18244 notifyOver : function(dd, e, data){
18245 return this.dropAllowed;
18249 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18250 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18251 * overClass (if any) from the drop element.
18252 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18253 * @param {Event} e The event
18254 * @param {Object} data An object containing arbitrary data supplied by the drag source
18256 notifyOut : function(dd, e, data){
18257 if(this.overClass){
18258 this.el.removeClass(this.overClass);
18263 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18264 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18265 * implementation that does something to process the drop event and returns true so that the drag source's
18266 * repair action does not run.
18267 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18268 * @param {Event} e The event
18269 * @param {Object} data An object containing arbitrary data supplied by the drag source
18270 * @return {Boolean} True if the drop was valid, else false
18272 notifyDrop : function(dd, e, data){
18277 * Ext JS Library 1.1.1
18278 * Copyright(c) 2006-2007, Ext JS, LLC.
18280 * Originally Released Under LGPL - original licence link has changed is not relivant.
18283 * <script type="text/javascript">
18288 * @class Roo.dd.DragZone
18289 * @extends Roo.dd.DragSource
18290 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18291 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18293 * @param {String/HTMLElement/Element} el The container element
18294 * @param {Object} config
18296 Roo.dd.DragZone = function(el, config){
18297 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18298 if(this.containerScroll){
18299 Roo.dd.ScrollManager.register(this.el);
18303 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18305 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18306 * for auto scrolling during drag operations.
18309 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18310 * method after a failed drop (defaults to "c3daf9" - light blue)
18314 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18315 * for a valid target to drag based on the mouse down. Override this method
18316 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18317 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18318 * @param {EventObject} e The mouse down event
18319 * @return {Object} The dragData
18321 getDragData : function(e){
18322 return Roo.dd.Registry.getHandleFromEvent(e);
18326 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18327 * this.dragData.ddel
18328 * @param {Number} x The x position of the click on the dragged object
18329 * @param {Number} y The y position of the click on the dragged object
18330 * @return {Boolean} true to continue the drag, false to cancel
18332 onInitDrag : function(x, y){
18333 this.proxy.update(this.dragData.ddel.cloneNode(true));
18334 this.onStartDrag(x, y);
18339 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18341 afterRepair : function(){
18343 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18345 this.dragging = false;
18349 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18350 * the XY of this.dragData.ddel
18351 * @param {EventObject} e The mouse up event
18352 * @return {Array} The xy location (e.g. [100, 200])
18354 getRepairXY : function(e){
18355 return Roo.Element.fly(this.dragData.ddel).getXY();
18359 * Ext JS Library 1.1.1
18360 * Copyright(c) 2006-2007, Ext JS, LLC.
18362 * Originally Released Under LGPL - original licence link has changed is not relivant.
18365 * <script type="text/javascript">
18368 * @class Roo.dd.DropZone
18369 * @extends Roo.dd.DropTarget
18370 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18371 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18373 * @param {String/HTMLElement/Element} el The container element
18374 * @param {Object} config
18376 Roo.dd.DropZone = function(el, config){
18377 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18380 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18382 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18383 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18384 * provide your own custom lookup.
18385 * @param {Event} e The event
18386 * @return {Object} data The custom data
18388 getTargetFromEvent : function(e){
18389 return Roo.dd.Registry.getTargetFromEvent(e);
18393 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18394 * that it has registered. This method has no default implementation and should be overridden to provide
18395 * node-specific processing if necessary.
18396 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18397 * {@link #getTargetFromEvent} for this node)
18398 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18399 * @param {Event} e The event
18400 * @param {Object} data An object containing arbitrary data supplied by the drag source
18402 onNodeEnter : function(n, dd, e, data){
18407 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18408 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18409 * overridden to provide the proper feedback.
18410 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18411 * {@link #getTargetFromEvent} for this node)
18412 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18413 * @param {Event} e The event
18414 * @param {Object} data An object containing arbitrary data supplied by the drag source
18415 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18416 * underlying {@link Roo.dd.StatusProxy} can be updated
18418 onNodeOver : function(n, dd, e, data){
18419 return this.dropAllowed;
18423 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18424 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18425 * node-specific processing if necessary.
18426 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18427 * {@link #getTargetFromEvent} for this node)
18428 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18429 * @param {Event} e The event
18430 * @param {Object} data An object containing arbitrary data supplied by the drag source
18432 onNodeOut : function(n, dd, e, data){
18437 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18438 * the drop node. The default implementation returns false, so it should be overridden to provide the
18439 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18440 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18441 * {@link #getTargetFromEvent} for this node)
18442 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18443 * @param {Event} e The event
18444 * @param {Object} data An object containing arbitrary data supplied by the drag source
18445 * @return {Boolean} True if the drop was valid, else false
18447 onNodeDrop : function(n, dd, e, data){
18452 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18453 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18454 * it should be overridden to provide the proper feedback if necessary.
18455 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18456 * @param {Event} e The event
18457 * @param {Object} data An object containing arbitrary data supplied by the drag source
18458 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18459 * underlying {@link Roo.dd.StatusProxy} can be updated
18461 onContainerOver : function(dd, e, data){
18462 return this.dropNotAllowed;
18466 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18467 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18468 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18469 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18470 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18471 * @param {Event} e The event
18472 * @param {Object} data An object containing arbitrary data supplied by the drag source
18473 * @return {Boolean} True if the drop was valid, else false
18475 onContainerDrop : function(dd, e, data){
18480 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18481 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18482 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18483 * you should override this method and provide a custom implementation.
18484 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18485 * @param {Event} e The event
18486 * @param {Object} data An object containing arbitrary data supplied by the drag source
18487 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18488 * underlying {@link Roo.dd.StatusProxy} can be updated
18490 notifyEnter : function(dd, e, data){
18491 return this.dropNotAllowed;
18495 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18496 * This method will be called on every mouse movement while the drag source is over the drop zone.
18497 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18498 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18499 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18500 * registered node, it will call {@link #onContainerOver}.
18501 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18502 * @param {Event} e The event
18503 * @param {Object} data An object containing arbitrary data supplied by the drag source
18504 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18505 * underlying {@link Roo.dd.StatusProxy} can be updated
18507 notifyOver : function(dd, e, data){
18508 var n = this.getTargetFromEvent(e);
18509 if(!n){ // not over valid drop target
18510 if(this.lastOverNode){
18511 this.onNodeOut(this.lastOverNode, dd, e, data);
18512 this.lastOverNode = null;
18514 return this.onContainerOver(dd, e, data);
18516 if(this.lastOverNode != n){
18517 if(this.lastOverNode){
18518 this.onNodeOut(this.lastOverNode, dd, e, data);
18520 this.onNodeEnter(n, dd, e, data);
18521 this.lastOverNode = n;
18523 return this.onNodeOver(n, dd, e, data);
18527 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18528 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18529 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18530 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18531 * @param {Event} e The event
18532 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18534 notifyOut : function(dd, e, data){
18535 if(this.lastOverNode){
18536 this.onNodeOut(this.lastOverNode, dd, e, data);
18537 this.lastOverNode = null;
18542 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18543 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18544 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18545 * otherwise it will call {@link #onContainerDrop}.
18546 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18547 * @param {Event} e The event
18548 * @param {Object} data An object containing arbitrary data supplied by the drag source
18549 * @return {Boolean} True if the drop was valid, else false
18551 notifyDrop : function(dd, e, data){
18552 if(this.lastOverNode){
18553 this.onNodeOut(this.lastOverNode, dd, e, data);
18554 this.lastOverNode = null;
18556 var n = this.getTargetFromEvent(e);
18558 this.onNodeDrop(n, dd, e, data) :
18559 this.onContainerDrop(dd, e, data);
18563 triggerCacheRefresh : function(){
18564 Roo.dd.DDM.refreshCache(this.groups);
18568 * Ext JS Library 1.1.1
18569 * Copyright(c) 2006-2007, Ext JS, LLC.
18571 * Originally Released Under LGPL - original licence link has changed is not relivant.
18574 * <script type="text/javascript">
18579 * @class Roo.data.SortTypes
18581 * Defines the default sorting (casting?) comparison functions used when sorting data.
18583 Roo.data.SortTypes = {
18585 * Default sort that does nothing
18586 * @param {Mixed} s The value being converted
18587 * @return {Mixed} The comparison value
18589 none : function(s){
18594 * The regular expression used to strip tags
18598 stripTagsRE : /<\/?[^>]+>/gi,
18601 * Strips all HTML tags to sort on text only
18602 * @param {Mixed} s The value being converted
18603 * @return {String} The comparison value
18605 asText : function(s){
18606 return String(s).replace(this.stripTagsRE, "");
18610 * Strips all HTML tags to sort on text only - Case insensitive
18611 * @param {Mixed} s The value being converted
18612 * @return {String} The comparison value
18614 asUCText : function(s){
18615 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18619 * Case insensitive string
18620 * @param {Mixed} s The value being converted
18621 * @return {String} The comparison value
18623 asUCString : function(s) {
18624 return String(s).toUpperCase();
18629 * @param {Mixed} s The value being converted
18630 * @return {Number} The comparison value
18632 asDate : function(s) {
18636 if(s instanceof Date){
18637 return s.getTime();
18639 return Date.parse(String(s));
18644 * @param {Mixed} s The value being converted
18645 * @return {Float} The comparison value
18647 asFloat : function(s) {
18648 var val = parseFloat(String(s).replace(/,/g, ""));
18649 if(isNaN(val)) val = 0;
18655 * @param {Mixed} s The value being converted
18656 * @return {Number} The comparison value
18658 asInt : function(s) {
18659 var val = parseInt(String(s).replace(/,/g, ""));
18660 if(isNaN(val)) val = 0;
18665 * Ext JS Library 1.1.1
18666 * Copyright(c) 2006-2007, Ext JS, LLC.
18668 * Originally Released Under LGPL - original licence link has changed is not relivant.
18671 * <script type="text/javascript">
18675 * @class Roo.data.Record
18676 * Instances of this class encapsulate both record <em>definition</em> information, and record
18677 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18678 * to access Records cached in an {@link Roo.data.Store} object.<br>
18680 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18681 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18684 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18686 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18687 * {@link #create}. The parameters are the same.
18688 * @param {Array} data An associative Array of data values keyed by the field name.
18689 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18690 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18691 * not specified an integer id is generated.
18693 Roo.data.Record = function(data, id){
18694 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18699 * Generate a constructor for a specific record layout.
18700 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18701 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18702 * Each field definition object may contain the following properties: <ul>
18703 * <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,
18704 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18705 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18706 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18707 * is being used, then this is a string containing the javascript expression to reference the data relative to
18708 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18709 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18710 * this may be omitted.</p></li>
18711 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18712 * <ul><li>auto (Default, implies no conversion)</li>
18717 * <li>date</li></ul></p></li>
18718 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18719 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18720 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18721 * by the Reader into an object that will be stored in the Record. It is passed the
18722 * following parameters:<ul>
18723 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18725 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18727 * <br>usage:<br><pre><code>
18728 var TopicRecord = Roo.data.Record.create(
18729 {name: 'title', mapping: 'topic_title'},
18730 {name: 'author', mapping: 'username'},
18731 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18732 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18733 {name: 'lastPoster', mapping: 'user2'},
18734 {name: 'excerpt', mapping: 'post_text'}
18737 var myNewRecord = new TopicRecord({
18738 title: 'Do my job please',
18741 lastPost: new Date(),
18742 lastPoster: 'Animal',
18743 excerpt: 'No way dude!'
18745 myStore.add(myNewRecord);
18750 Roo.data.Record.create = function(o){
18751 var f = function(){
18752 f.superclass.constructor.apply(this, arguments);
18754 Roo.extend(f, Roo.data.Record);
18755 var p = f.prototype;
18756 p.fields = new Roo.util.MixedCollection(false, function(field){
18759 for(var i = 0, len = o.length; i < len; i++){
18760 p.fields.add(new Roo.data.Field(o[i]));
18762 f.getField = function(name){
18763 return p.fields.get(name);
18768 Roo.data.Record.AUTO_ID = 1000;
18769 Roo.data.Record.EDIT = 'edit';
18770 Roo.data.Record.REJECT = 'reject';
18771 Roo.data.Record.COMMIT = 'commit';
18773 Roo.data.Record.prototype = {
18775 * Readonly flag - true if this record has been modified.
18784 join : function(store){
18785 this.store = store;
18789 * Set the named field to the specified value.
18790 * @param {String} name The name of the field to set.
18791 * @param {Object} value The value to set the field to.
18793 set : function(name, value){
18794 if(this.data[name] == value){
18798 if(!this.modified){
18799 this.modified = {};
18801 if(typeof this.modified[name] == 'undefined'){
18802 this.modified[name] = this.data[name];
18804 this.data[name] = value;
18806 this.store.afterEdit(this);
18811 * Get the value of the named field.
18812 * @param {String} name The name of the field to get the value of.
18813 * @return {Object} The value of the field.
18815 get : function(name){
18816 return this.data[name];
18820 beginEdit : function(){
18821 this.editing = true;
18822 this.modified = {};
18826 cancelEdit : function(){
18827 this.editing = false;
18828 delete this.modified;
18832 endEdit : function(){
18833 this.editing = false;
18834 if(this.dirty && this.store){
18835 this.store.afterEdit(this);
18840 * Usually called by the {@link Roo.data.Store} which owns the Record.
18841 * Rejects all changes made to the Record since either creation, or the last commit operation.
18842 * Modified fields are reverted to their original values.
18844 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18845 * of reject operations.
18847 reject : function(){
18848 var m = this.modified;
18850 if(typeof m[n] != "function"){
18851 this.data[n] = m[n];
18854 this.dirty = false;
18855 delete this.modified;
18856 this.editing = false;
18858 this.store.afterReject(this);
18863 * Usually called by the {@link Roo.data.Store} which owns the Record.
18864 * Commits all changes made to the Record since either creation, or the last commit operation.
18866 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18867 * of commit operations.
18869 commit : function(){
18870 this.dirty = false;
18871 delete this.modified;
18872 this.editing = false;
18874 this.store.afterCommit(this);
18879 hasError : function(){
18880 return this.error != null;
18884 clearError : function(){
18889 * Creates a copy of this record.
18890 * @param {String} id (optional) A new record id if you don't want to use this record's id
18893 copy : function(newId) {
18894 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
18898 * Ext JS Library 1.1.1
18899 * Copyright(c) 2006-2007, Ext JS, LLC.
18901 * Originally Released Under LGPL - original licence link has changed is not relivant.
18904 * <script type="text/javascript">
18910 * @class Roo.data.Store
18911 * @extends Roo.util.Observable
18912 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
18913 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
18915 * 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
18916 * has no knowledge of the format of the data returned by the Proxy.<br>
18918 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
18919 * instances from the data object. These records are cached and made available through accessor functions.
18921 * Creates a new Store.
18922 * @param {Object} config A config object containing the objects needed for the Store to access data,
18923 * and read the data into Records.
18925 Roo.data.Store = function(config){
18926 this.data = new Roo.util.MixedCollection(false);
18927 this.data.getKey = function(o){
18930 this.baseParams = {};
18932 this.paramNames = {
18939 if(config && config.data){
18940 this.inlineData = config.data;
18941 delete config.data;
18944 Roo.apply(this, config);
18946 if(this.reader){ // reader passed
18947 this.reader = Roo.factory(this.reader, Roo.data);
18948 this.reader.xmodule = this.xmodule || false;
18949 if(!this.recordType){
18950 this.recordType = this.reader.recordType;
18952 if(this.reader.onMetaChange){
18953 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
18957 if(this.recordType){
18958 this.fields = this.recordType.prototype.fields;
18960 this.modified = [];
18964 * @event datachanged
18965 * Fires when the data cache has changed, and a widget which is using this Store
18966 * as a Record cache should refresh its view.
18967 * @param {Store} this
18969 datachanged : true,
18971 * @event metachange
18972 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
18973 * @param {Store} this
18974 * @param {Object} meta The JSON metadata
18979 * Fires when Records have been added to the Store
18980 * @param {Store} this
18981 * @param {Roo.data.Record[]} records The array of Records added
18982 * @param {Number} index The index at which the record(s) were added
18987 * Fires when a Record has been removed from the Store
18988 * @param {Store} this
18989 * @param {Roo.data.Record} record The Record that was removed
18990 * @param {Number} index The index at which the record was removed
18995 * Fires when a Record has been updated
18996 * @param {Store} this
18997 * @param {Roo.data.Record} record The Record that was updated
18998 * @param {String} operation The update operation being performed. Value may be one of:
19000 Roo.data.Record.EDIT
19001 Roo.data.Record.REJECT
19002 Roo.data.Record.COMMIT
19008 * Fires when the data cache has been cleared.
19009 * @param {Store} this
19013 * @event beforeload
19014 * Fires before a request is made for a new data object. If the beforeload handler returns false
19015 * the load action will be canceled.
19016 * @param {Store} this
19017 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19022 * Fires after a new set of Records has been loaded.
19023 * @param {Store} this
19024 * @param {Roo.data.Record[]} records The Records that were loaded
19025 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19029 * @event loadexception
19030 * Fires if an exception occurs in the Proxy during loading.
19031 * Called with the signature of the Proxy's "loadexception" event.
19032 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19035 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19036 * @param {Object} load options
19037 * @param {Object} jsonData from your request (normally this contains the Exception)
19039 loadexception : true
19043 this.proxy = Roo.factory(this.proxy, Roo.data);
19044 this.proxy.xmodule = this.xmodule || false;
19045 this.relayEvents(this.proxy, ["loadexception"]);
19047 this.sortToggle = {};
19049 Roo.data.Store.superclass.constructor.call(this);
19051 if(this.inlineData){
19052 this.loadData(this.inlineData);
19053 delete this.inlineData;
19056 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19058 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19059 * without a remote query - used by combo/forms at present.
19063 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19066 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19069 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19070 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19073 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19074 * on any HTTP request
19077 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19080 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19081 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19083 remoteSort : false,
19086 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19087 * loaded or when a record is removed. (defaults to false).
19089 pruneModifiedRecords : false,
19092 lastOptions : null,
19095 * Add Records to the Store and fires the add event.
19096 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19098 add : function(records){
19099 records = [].concat(records);
19100 for(var i = 0, len = records.length; i < len; i++){
19101 records[i].join(this);
19103 var index = this.data.length;
19104 this.data.addAll(records);
19105 this.fireEvent("add", this, records, index);
19109 * Remove a Record from the Store and fires the remove event.
19110 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19112 remove : function(record){
19113 var index = this.data.indexOf(record);
19114 this.data.removeAt(index);
19115 if(this.pruneModifiedRecords){
19116 this.modified.remove(record);
19118 this.fireEvent("remove", this, record, index);
19122 * Remove all Records from the Store and fires the clear event.
19124 removeAll : function(){
19126 if(this.pruneModifiedRecords){
19127 this.modified = [];
19129 this.fireEvent("clear", this);
19133 * Inserts Records to the Store at the given index and fires the add event.
19134 * @param {Number} index The start index at which to insert the passed Records.
19135 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19137 insert : function(index, records){
19138 records = [].concat(records);
19139 for(var i = 0, len = records.length; i < len; i++){
19140 this.data.insert(index, records[i]);
19141 records[i].join(this);
19143 this.fireEvent("add", this, records, index);
19147 * Get the index within the cache of the passed Record.
19148 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19149 * @return {Number} The index of the passed Record. Returns -1 if not found.
19151 indexOf : function(record){
19152 return this.data.indexOf(record);
19156 * Get the index within the cache of the Record with the passed id.
19157 * @param {String} id The id of the Record to find.
19158 * @return {Number} The index of the Record. Returns -1 if not found.
19160 indexOfId : function(id){
19161 return this.data.indexOfKey(id);
19165 * Get the Record with the specified id.
19166 * @param {String} id The id of the Record to find.
19167 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19169 getById : function(id){
19170 return this.data.key(id);
19174 * Get the Record at the specified index.
19175 * @param {Number} index The index of the Record to find.
19176 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19178 getAt : function(index){
19179 return this.data.itemAt(index);
19183 * Returns a range of Records between specified indices.
19184 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19185 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19186 * @return {Roo.data.Record[]} An array of Records
19188 getRange : function(start, end){
19189 return this.data.getRange(start, end);
19193 storeOptions : function(o){
19194 o = Roo.apply({}, o);
19197 this.lastOptions = o;
19201 * Loads the Record cache from the configured Proxy using the configured Reader.
19203 * If using remote paging, then the first load call must specify the <em>start</em>
19204 * and <em>limit</em> properties in the options.params property to establish the initial
19205 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19207 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19208 * and this call will return before the new data has been loaded. Perform any post-processing
19209 * in a callback function, or in a "load" event handler.</strong>
19211 * @param {Object} options An object containing properties which control loading options:<ul>
19212 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19213 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19214 * passed the following arguments:<ul>
19215 * <li>r : Roo.data.Record[]</li>
19216 * <li>options: Options object from the load call</li>
19217 * <li>success: Boolean success indicator</li></ul></li>
19218 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19219 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19222 load : function(options){
19223 options = options || {};
19224 if(this.fireEvent("beforeload", this, options) !== false){
19225 this.storeOptions(options);
19226 var p = Roo.apply(options.params || {}, this.baseParams);
19227 if(this.sortInfo && this.remoteSort){
19228 var pn = this.paramNames;
19229 p[pn["sort"]] = this.sortInfo.field;
19230 p[pn["dir"]] = this.sortInfo.direction;
19232 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19237 * Reloads the Record cache from the configured Proxy using the configured Reader and
19238 * the options from the last load operation performed.
19239 * @param {Object} options (optional) An object containing properties which may override the options
19240 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19241 * the most recently used options are reused).
19243 reload : function(options){
19244 this.load(Roo.applyIf(options||{}, this.lastOptions));
19248 // Called as a callback by the Reader during a load operation.
19249 loadRecords : function(o, options, success){
19250 if(!o || success === false){
19251 if(success !== false){
19252 this.fireEvent("load", this, [], options);
19254 if(options.callback){
19255 options.callback.call(options.scope || this, [], options, false);
19259 // if data returned failure - throw an exception.
19260 if (o.success === false) {
19261 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19264 var r = o.records, t = o.totalRecords || r.length;
19265 if(!options || options.add !== true){
19266 if(this.pruneModifiedRecords){
19267 this.modified = [];
19269 for(var i = 0, len = r.length; i < len; i++){
19273 this.data = this.snapshot;
19274 delete this.snapshot;
19277 this.data.addAll(r);
19278 this.totalLength = t;
19280 this.fireEvent("datachanged", this);
19282 this.totalLength = Math.max(t, this.data.length+r.length);
19285 this.fireEvent("load", this, r, options);
19286 if(options.callback){
19287 options.callback.call(options.scope || this, r, options, true);
19292 * Loads data from a passed data block. A Reader which understands the format of the data
19293 * must have been configured in the constructor.
19294 * @param {Object} data The data block from which to read the Records. The format of the data expected
19295 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19296 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19298 loadData : function(o, append){
19299 var r = this.reader.readRecords(o);
19300 this.loadRecords(r, {add: append}, true);
19304 * Gets the number of cached records.
19306 * <em>If using paging, this may not be the total size of the dataset. If the data object
19307 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19308 * the data set size</em>
19310 getCount : function(){
19311 return this.data.length || 0;
19315 * Gets the total number of records in the dataset as returned by the server.
19317 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19318 * the dataset size</em>
19320 getTotalCount : function(){
19321 return this.totalLength || 0;
19325 * Returns the sort state of the Store as an object with two properties:
19327 field {String} The name of the field by which the Records are sorted
19328 direction {String} The sort order, "ASC" or "DESC"
19331 getSortState : function(){
19332 return this.sortInfo;
19336 applySort : function(){
19337 if(this.sortInfo && !this.remoteSort){
19338 var s = this.sortInfo, f = s.field;
19339 var st = this.fields.get(f).sortType;
19340 var fn = function(r1, r2){
19341 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19342 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19344 this.data.sort(s.direction, fn);
19345 if(this.snapshot && this.snapshot != this.data){
19346 this.snapshot.sort(s.direction, fn);
19352 * Sets the default sort column and order to be used by the next load operation.
19353 * @param {String} fieldName The name of the field to sort by.
19354 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19356 setDefaultSort : function(field, dir){
19357 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19361 * Sort the Records.
19362 * If remote sorting is used, the sort is performed on the server, and the cache is
19363 * reloaded. If local sorting is used, the cache is sorted internally.
19364 * @param {String} fieldName The name of the field to sort by.
19365 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19367 sort : function(fieldName, dir){
19368 var f = this.fields.get(fieldName);
19370 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19371 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19376 this.sortToggle[f.name] = dir;
19377 this.sortInfo = {field: f.name, direction: dir};
19378 if(!this.remoteSort){
19380 this.fireEvent("datachanged", this);
19382 this.load(this.lastOptions);
19387 * Calls the specified function for each of the Records in the cache.
19388 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19389 * Returning <em>false</em> aborts and exits the iteration.
19390 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19392 each : function(fn, scope){
19393 this.data.each(fn, scope);
19397 * Gets all records modified since the last commit. Modified records are persisted across load operations
19398 * (e.g., during paging).
19399 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19401 getModifiedRecords : function(){
19402 return this.modified;
19406 createFilterFn : function(property, value, anyMatch){
19407 if(!value.exec){ // not a regex
19408 value = String(value);
19409 if(value.length == 0){
19412 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19414 return function(r){
19415 return value.test(r.data[property]);
19420 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19421 * @param {String} property A field on your records
19422 * @param {Number} start The record index to start at (defaults to 0)
19423 * @param {Number} end The last record index to include (defaults to length - 1)
19424 * @return {Number} The sum
19426 sum : function(property, start, end){
19427 var rs = this.data.items, v = 0;
19428 start = start || 0;
19429 end = (end || end === 0) ? end : rs.length-1;
19431 for(var i = start; i <= end; i++){
19432 v += (rs[i].data[property] || 0);
19438 * Filter the records by a specified property.
19439 * @param {String} field A field on your records
19440 * @param {String/RegExp} value Either a string that the field
19441 * should start with or a RegExp to test against the field
19442 * @param {Boolean} anyMatch True to match any part not just the beginning
19444 filter : function(property, value, anyMatch){
19445 var fn = this.createFilterFn(property, value, anyMatch);
19446 return fn ? this.filterBy(fn) : this.clearFilter();
19450 * Filter by a function. The specified function will be called with each
19451 * record in this data source. If the function returns true the record is included,
19452 * otherwise it is filtered.
19453 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19454 * @param {Object} scope (optional) The scope of the function (defaults to this)
19456 filterBy : function(fn, scope){
19457 this.snapshot = this.snapshot || this.data;
19458 this.data = this.queryBy(fn, scope||this);
19459 this.fireEvent("datachanged", this);
19463 * Query the records by a specified property.
19464 * @param {String} field A field on your records
19465 * @param {String/RegExp} value Either a string that the field
19466 * should start with or a RegExp to test against the field
19467 * @param {Boolean} anyMatch True to match any part not just the beginning
19468 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19470 query : function(property, value, anyMatch){
19471 var fn = this.createFilterFn(property, value, anyMatch);
19472 return fn ? this.queryBy(fn) : this.data.clone();
19476 * Query by a function. The specified function will be called with each
19477 * record in this data source. If the function returns true the record is included
19479 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19480 * @param {Object} scope (optional) The scope of the function (defaults to this)
19481 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19483 queryBy : function(fn, scope){
19484 var data = this.snapshot || this.data;
19485 return data.filterBy(fn, scope||this);
19489 * Collects unique values for a particular dataIndex from this store.
19490 * @param {String} dataIndex The property to collect
19491 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19492 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19493 * @return {Array} An array of the unique values
19495 collect : function(dataIndex, allowNull, bypassFilter){
19496 var d = (bypassFilter === true && this.snapshot) ?
19497 this.snapshot.items : this.data.items;
19498 var v, sv, r = [], l = {};
19499 for(var i = 0, len = d.length; i < len; i++){
19500 v = d[i].data[dataIndex];
19502 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19511 * Revert to a view of the Record cache with no filtering applied.
19512 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19514 clearFilter : function(suppressEvent){
19515 if(this.snapshot && this.snapshot != this.data){
19516 this.data = this.snapshot;
19517 delete this.snapshot;
19518 if(suppressEvent !== true){
19519 this.fireEvent("datachanged", this);
19525 afterEdit : function(record){
19526 if(this.modified.indexOf(record) == -1){
19527 this.modified.push(record);
19529 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19533 afterReject : function(record){
19534 this.modified.remove(record);
19535 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19539 afterCommit : function(record){
19540 this.modified.remove(record);
19541 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19545 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19546 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19548 commitChanges : function(){
19549 var m = this.modified.slice(0);
19550 this.modified = [];
19551 for(var i = 0, len = m.length; i < len; i++){
19557 * Cancel outstanding changes on all changed records.
19559 rejectChanges : function(){
19560 var m = this.modified.slice(0);
19561 this.modified = [];
19562 for(var i = 0, len = m.length; i < len; i++){
19567 onMetaChange : function(meta, rtype, o){
19568 this.recordType = rtype;
19569 this.fields = rtype.prototype.fields;
19570 delete this.snapshot;
19571 this.sortInfo = meta.sortInfo;
19572 this.modified = [];
19573 this.fireEvent('metachange', this, this.reader.meta);
19577 * Ext JS Library 1.1.1
19578 * Copyright(c) 2006-2007, Ext JS, LLC.
19580 * Originally Released Under LGPL - original licence link has changed is not relivant.
19583 * <script type="text/javascript">
19587 * @class Roo.data.SimpleStore
19588 * @extends Roo.data.Store
19589 * Small helper class to make creating Stores from Array data easier.
19590 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19591 * @cfg {Array} fields An array of field definition objects, or field name strings.
19592 * @cfg {Array} data The multi-dimensional array of data
19594 * @param {Object} config
19596 Roo.data.SimpleStore = function(config){
19597 Roo.data.SimpleStore.superclass.constructor.call(this, {
19599 reader: new Roo.data.ArrayReader({
19602 Roo.data.Record.create(config.fields)
19604 proxy : new Roo.data.MemoryProxy(config.data)
19608 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19610 * Ext JS Library 1.1.1
19611 * Copyright(c) 2006-2007, Ext JS, LLC.
19613 * Originally Released Under LGPL - original licence link has changed is not relivant.
19616 * <script type="text/javascript">
19621 * @extends Roo.data.Store
19622 * @class Roo.data.JsonStore
19623 * Small helper class to make creating Stores for JSON data easier. <br/>
19625 var store = new Roo.data.JsonStore({
19626 url: 'get-images.php',
19628 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19631 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19632 * JsonReader and HttpProxy (unless inline data is provided).</b>
19633 * @cfg {Array} fields An array of field definition objects, or field name strings.
19635 * @param {Object} config
19637 Roo.data.JsonStore = function(c){
19638 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19639 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19640 reader: new Roo.data.JsonReader(c, c.fields)
19643 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19645 * Ext JS Library 1.1.1
19646 * Copyright(c) 2006-2007, Ext JS, LLC.
19648 * Originally Released Under LGPL - original licence link has changed is not relivant.
19651 * <script type="text/javascript">
19655 Roo.data.Field = function(config){
19656 if(typeof config == "string"){
19657 config = {name: config};
19659 Roo.apply(this, config);
19662 this.type = "auto";
19665 var st = Roo.data.SortTypes;
19666 // named sortTypes are supported, here we look them up
19667 if(typeof this.sortType == "string"){
19668 this.sortType = st[this.sortType];
19671 // set default sortType for strings and dates
19672 if(!this.sortType){
19675 this.sortType = st.asUCString;
19678 this.sortType = st.asDate;
19681 this.sortType = st.none;
19686 var stripRe = /[\$,%]/g;
19688 // prebuilt conversion function for this field, instead of
19689 // switching every time we're reading a value
19691 var cv, dateFormat = this.dateFormat;
19696 cv = function(v){ return v; };
19699 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19703 return v !== undefined && v !== null && v !== '' ?
19704 parseInt(String(v).replace(stripRe, ""), 10) : '';
19709 return v !== undefined && v !== null && v !== '' ?
19710 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19715 cv = function(v){ return v === true || v === "true" || v == 1; };
19722 if(v instanceof Date){
19726 if(dateFormat == "timestamp"){
19727 return new Date(v*1000);
19729 return Date.parseDate(v, dateFormat);
19731 var parsed = Date.parse(v);
19732 return parsed ? new Date(parsed) : null;
19741 Roo.data.Field.prototype = {
19749 * Ext JS Library 1.1.1
19750 * Copyright(c) 2006-2007, Ext JS, LLC.
19752 * Originally Released Under LGPL - original licence link has changed is not relivant.
19755 * <script type="text/javascript">
19758 // Base class for reading structured data from a data source. This class is intended to be
19759 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19762 * @class Roo.data.DataReader
19763 * Base class for reading structured data from a data source. This class is intended to be
19764 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19767 Roo.data.DataReader = function(meta, recordType){
19771 this.recordType = recordType instanceof Array ?
19772 Roo.data.Record.create(recordType) : recordType;
19775 Roo.data.DataReader.prototype = {
19777 * Create an empty record
19778 * @param {Object} data (optional) - overlay some values
19779 * @return {Roo.data.Record} record created.
19781 newRow : function(d) {
19783 this.recordType.prototype.fields.each(function(c) {
19785 case 'int' : da[c.name] = 0; break;
19786 case 'date' : da[c.name] = new Date(); break;
19787 case 'float' : da[c.name] = 0.0; break;
19788 case 'boolean' : da[c.name] = false; break;
19789 default : da[c.name] = ""; break;
19793 return new this.recordType(Roo.apply(da, d));
19798 * Ext JS Library 1.1.1
19799 * Copyright(c) 2006-2007, Ext JS, LLC.
19801 * Originally Released Under LGPL - original licence link has changed is not relivant.
19804 * <script type="text/javascript">
19808 * @class Roo.data.DataProxy
19809 * @extends Roo.data.Observable
19810 * This class is an abstract base class for implementations which provide retrieval of
19811 * unformatted data objects.<br>
19813 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19814 * (of the appropriate type which knows how to parse the data object) to provide a block of
19815 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19817 * Custom implementations must implement the load method as described in
19818 * {@link Roo.data.HttpProxy#load}.
19820 Roo.data.DataProxy = function(){
19823 * @event beforeload
19824 * Fires before a network request is made to retrieve a data object.
19825 * @param {Object} This DataProxy object.
19826 * @param {Object} params The params parameter to the load function.
19831 * Fires before the load method's callback is called.
19832 * @param {Object} This DataProxy object.
19833 * @param {Object} o The data object.
19834 * @param {Object} arg The callback argument object passed to the load function.
19838 * @event loadexception
19839 * Fires if an Exception occurs during data retrieval.
19840 * @param {Object} This DataProxy object.
19841 * @param {Object} o The data object.
19842 * @param {Object} arg The callback argument object passed to the load function.
19843 * @param {Object} e The Exception.
19845 loadexception : true
19847 Roo.data.DataProxy.superclass.constructor.call(this);
19850 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
19853 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
19857 * Ext JS Library 1.1.1
19858 * Copyright(c) 2006-2007, Ext JS, LLC.
19860 * Originally Released Under LGPL - original licence link has changed is not relivant.
19863 * <script type="text/javascript">
19866 * @class Roo.data.MemoryProxy
19867 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
19868 * to the Reader when its load method is called.
19870 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
19872 Roo.data.MemoryProxy = function(data){
19876 Roo.data.MemoryProxy.superclass.constructor.call(this);
19880 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
19882 * Load data from the requested source (in this case an in-memory
19883 * data object passed to the constructor), read the data object into
19884 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
19885 * process that block using the passed callback.
19886 * @param {Object} params This parameter is not used by the MemoryProxy class.
19887 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19888 * object into a block of Roo.data.Records.
19889 * @param {Function} callback The function into which to pass the block of Roo.data.records.
19890 * The function must be passed <ul>
19891 * <li>The Record block object</li>
19892 * <li>The "arg" argument from the load function</li>
19893 * <li>A boolean success indicator</li>
19895 * @param {Object} scope The scope in which to call the callback
19896 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19898 load : function(params, reader, callback, scope, arg){
19899 params = params || {};
19902 result = reader.readRecords(this.data);
19904 this.fireEvent("loadexception", this, arg, null, e);
19905 callback.call(scope, null, arg, false);
19908 callback.call(scope, result, arg, true);
19912 update : function(params, records){
19917 * Ext JS Library 1.1.1
19918 * Copyright(c) 2006-2007, Ext JS, LLC.
19920 * Originally Released Under LGPL - original licence link has changed is not relivant.
19923 * <script type="text/javascript">
19926 * @class Roo.data.HttpProxy
19927 * @extends Roo.data.DataProxy
19928 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
19929 * configured to reference a certain URL.<br><br>
19931 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
19932 * from which the running page was served.<br><br>
19934 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
19936 * Be aware that to enable the browser to parse an XML document, the server must set
19937 * the Content-Type header in the HTTP response to "text/xml".
19939 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
19940 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
19941 * will be used to make the request.
19943 Roo.data.HttpProxy = function(conn){
19944 Roo.data.HttpProxy.superclass.constructor.call(this);
19945 // is conn a conn config or a real conn?
19947 this.useAjax = !conn || !conn.events;
19951 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
19952 // thse are take from connection...
19955 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
19958 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
19959 * extra parameters to each request made by this object. (defaults to undefined)
19962 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
19963 * to each request made by this object. (defaults to undefined)
19966 * @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)
19969 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
19972 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
19978 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
19982 * Return the {@link Roo.data.Connection} object being used by this Proxy.
19983 * @return {Connection} The Connection object. This object may be used to subscribe to events on
19984 * a finer-grained basis than the DataProxy events.
19986 getConnection : function(){
19987 return this.useAjax ? Roo.Ajax : this.conn;
19991 * Load data from the configured {@link Roo.data.Connection}, read the data object into
19992 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
19993 * process that block using the passed callback.
19994 * @param {Object} params An object containing properties which are to be used as HTTP parameters
19995 * for the request to the remote server.
19996 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19997 * object into a block of Roo.data.Records.
19998 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
19999 * The function must be passed <ul>
20000 * <li>The Record block object</li>
20001 * <li>The "arg" argument from the load function</li>
20002 * <li>A boolean success indicator</li>
20004 * @param {Object} scope The scope in which to call the callback
20005 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20007 load : function(params, reader, callback, scope, arg){
20008 if(this.fireEvent("beforeload", this, params) !== false){
20010 params : params || {},
20012 callback : callback,
20017 callback : this.loadResponse,
20021 Roo.applyIf(o, this.conn);
20022 if(this.activeRequest){
20023 Roo.Ajax.abort(this.activeRequest);
20025 this.activeRequest = Roo.Ajax.request(o);
20027 this.conn.request(o);
20030 callback.call(scope||this, null, arg, false);
20035 loadResponse : function(o, success, response){
20036 delete this.activeRequest;
20038 this.fireEvent("loadexception", this, o, response);
20039 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20044 result = o.reader.read(response);
20046 this.fireEvent("loadexception", this, o, response, e);
20047 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20051 this.fireEvent("load", this, o, o.request.arg);
20052 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20056 update : function(dataSet){
20061 updateResponse : function(dataSet){
20066 * Ext JS Library 1.1.1
20067 * Copyright(c) 2006-2007, Ext JS, LLC.
20069 * Originally Released Under LGPL - original licence link has changed is not relivant.
20072 * <script type="text/javascript">
20076 * @class Roo.data.ScriptTagProxy
20077 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20078 * other than the originating domain of the running page.<br><br>
20080 * <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
20081 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20083 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20084 * source code that is used as the source inside a <script> tag.<br><br>
20086 * In order for the browser to process the returned data, the server must wrap the data object
20087 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20088 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20089 * depending on whether the callback name was passed:
20092 boolean scriptTag = false;
20093 String cb = request.getParameter("callback");
20096 response.setContentType("text/javascript");
20098 response.setContentType("application/x-json");
20100 Writer out = response.getWriter();
20102 out.write(cb + "(");
20104 out.print(dataBlock.toJsonString());
20111 * @param {Object} config A configuration object.
20113 Roo.data.ScriptTagProxy = function(config){
20114 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20115 Roo.apply(this, config);
20116 this.head = document.getElementsByTagName("head")[0];
20119 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20121 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20123 * @cfg {String} url The URL from which to request the data object.
20126 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20130 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20131 * the server the name of the callback function set up by the load call to process the returned data object.
20132 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20133 * javascript output which calls this named function passing the data object as its only parameter.
20135 callbackParam : "callback",
20137 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20138 * name to the request.
20143 * Load data from the configured URL, read the data object into
20144 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20145 * process that block using the passed callback.
20146 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20147 * for the request to the remote server.
20148 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20149 * object into a block of Roo.data.Records.
20150 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20151 * The function must be passed <ul>
20152 * <li>The Record block object</li>
20153 * <li>The "arg" argument from the load function</li>
20154 * <li>A boolean success indicator</li>
20156 * @param {Object} scope The scope in which to call the callback
20157 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20159 load : function(params, reader, callback, scope, arg){
20160 if(this.fireEvent("beforeload", this, params) !== false){
20162 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20164 var url = this.url;
20165 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20167 url += "&_dc=" + (new Date().getTime());
20169 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20172 cb : "stcCallback"+transId,
20173 scriptId : "stcScript"+transId,
20177 callback : callback,
20183 window[trans.cb] = function(o){
20184 conn.handleResponse(o, trans);
20187 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20189 if(this.autoAbort !== false){
20193 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20195 var script = document.createElement("script");
20196 script.setAttribute("src", url);
20197 script.setAttribute("type", "text/javascript");
20198 script.setAttribute("id", trans.scriptId);
20199 this.head.appendChild(script);
20201 this.trans = trans;
20203 callback.call(scope||this, null, arg, false);
20208 isLoading : function(){
20209 return this.trans ? true : false;
20213 * Abort the current server request.
20215 abort : function(){
20216 if(this.isLoading()){
20217 this.destroyTrans(this.trans);
20222 destroyTrans : function(trans, isLoaded){
20223 this.head.removeChild(document.getElementById(trans.scriptId));
20224 clearTimeout(trans.timeoutId);
20226 window[trans.cb] = undefined;
20228 delete window[trans.cb];
20231 // if hasn't been loaded, wait for load to remove it to prevent script error
20232 window[trans.cb] = function(){
20233 window[trans.cb] = undefined;
20235 delete window[trans.cb];
20242 handleResponse : function(o, trans){
20243 this.trans = false;
20244 this.destroyTrans(trans, true);
20247 result = trans.reader.readRecords(o);
20249 this.fireEvent("loadexception", this, o, trans.arg, e);
20250 trans.callback.call(trans.scope||window, null, trans.arg, false);
20253 this.fireEvent("load", this, o, trans.arg);
20254 trans.callback.call(trans.scope||window, result, trans.arg, true);
20258 handleFailure : function(trans){
20259 this.trans = false;
20260 this.destroyTrans(trans, false);
20261 this.fireEvent("loadexception", this, null, trans.arg);
20262 trans.callback.call(trans.scope||window, null, trans.arg, false);
20266 * Ext JS Library 1.1.1
20267 * Copyright(c) 2006-2007, Ext JS, LLC.
20269 * Originally Released Under LGPL - original licence link has changed is not relivant.
20272 * <script type="text/javascript">
20276 * @class Roo.data.JsonReader
20277 * @extends Roo.data.DataReader
20278 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20279 * based on mappings in a provided Roo.data.Record constructor.
20283 var RecordDef = Roo.data.Record.create([
20284 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20285 {name: 'occupation'} // This field will use "occupation" as the mapping.
20287 var myReader = new Roo.data.JsonReader({
20288 totalProperty: "results", // The property which contains the total dataset size (optional)
20289 root: "rows", // The property which contains an Array of row objects
20290 id: "id" // The property within each row object that provides an ID for the record (optional)
20294 * This would consume a JSON file like this:
20296 { 'results': 2, 'rows': [
20297 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20298 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20301 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20302 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20303 * paged from the remote server.
20304 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20305 * @cfg {String} root name of the property which contains the Array of row objects.
20306 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20308 * Create a new JsonReader
20309 * @param {Object} meta Metadata configuration options
20310 * @param {Object} recordType Either an Array of field definition objects,
20311 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20313 Roo.data.JsonReader = function(meta, recordType){
20316 // set some defaults:
20317 Roo.applyIf(meta, {
20318 totalProperty: 'total',
20319 successProperty : 'success',
20324 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20326 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20328 * This method is only used by a DataProxy which has retrieved data from a remote server.
20329 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20330 * @return {Object} data A data block which is used by an Roo.data.Store object as
20331 * a cache of Roo.data.Records.
20333 read : function(response){
20334 var json = response.responseText;
20336 var o = eval("("+json+")");
20338 throw {message: "JsonReader.read: Json object not found"};
20343 this.meta = o.metaData;
20344 this.recordType = Roo.data.Record.create(o.metaData.fields);
20345 this.onMetaChange(this.meta, this.recordType, o);
20347 return this.readRecords(o);
20350 // private function a store will implement
20351 onMetaChange : function(meta, recordType, o){
20358 simpleAccess: function(obj, subsc) {
20365 getJsonAccessor: function(){
20367 return function(expr) {
20369 return(re.test(expr))
20370 ? new Function("obj", "return obj." + expr)
20375 return Roo.emptyFn;
20380 * Create a data block containing Roo.data.Records from an XML document.
20381 * @param {Object} o An object which contains an Array of row objects in the property specified
20382 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20383 * which contains the total size of the dataset.
20384 * @return {Object} data A data block which is used by an Roo.data.Store object as
20385 * a cache of Roo.data.Records.
20387 readRecords : function(o){
20389 * After any data loads, the raw JSON data is available for further custom processing.
20393 var s = this.meta, Record = this.recordType,
20394 f = Record.prototype.fields, fi = f.items, fl = f.length;
20396 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20398 if(s.totalProperty) {
20399 this.getTotal = this.getJsonAccessor(s.totalProperty);
20401 if(s.successProperty) {
20402 this.getSuccess = this.getJsonAccessor(s.successProperty);
20404 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20406 var g = this.getJsonAccessor(s.id);
20407 this.getId = function(rec) {
20409 return (r === undefined || r === "") ? null : r;
20412 this.getId = function(){return null;};
20415 for(var i = 0; i < fl; i++){
20417 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20418 this.ef[i] = this.getJsonAccessor(map);
20422 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20423 if(s.totalProperty){
20424 var v = parseInt(this.getTotal(o), 10);
20429 if(s.successProperty){
20430 var v = this.getSuccess(o);
20431 if(v === false || v === 'false'){
20436 for(var i = 0; i < c; i++){
20439 var id = this.getId(n);
20440 for(var j = 0; j < fl; j++){
20442 var v = this.ef[j](n);
20443 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20445 var record = new Record(values, id);
20447 records[i] = record;
20452 totalRecords : totalRecords
20457 * Ext JS Library 1.1.1
20458 * Copyright(c) 2006-2007, Ext JS, LLC.
20460 * Originally Released Under LGPL - original licence link has changed is not relivant.
20463 * <script type="text/javascript">
20467 * @class Roo.data.XmlReader
20468 * @extends Roo.data.DataReader
20469 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20470 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20472 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20473 * header in the HTTP response must be set to "text/xml".</em>
20477 var RecordDef = Roo.data.Record.create([
20478 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20479 {name: 'occupation'} // This field will use "occupation" as the mapping.
20481 var myReader = new Roo.data.XmlReader({
20482 totalRecords: "results", // The element which contains the total dataset size (optional)
20483 record: "row", // The repeated element which contains row information
20484 id: "id" // The element within the row that provides an ID for the record (optional)
20488 * This would consume an XML file like this:
20492 <results>2</results>
20495 <name>Bill</name>
20496 <occupation>Gardener</occupation>
20500 <name>Ben</name>
20501 <occupation>Horticulturalist</occupation>
20505 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20506 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20507 * paged from the remote server.
20508 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20509 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20510 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20511 * a record identifier value.
20513 * Create a new XmlReader
20514 * @param {Object} meta Metadata configuration options
20515 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20516 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20517 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20519 Roo.data.XmlReader = function(meta, recordType){
20521 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20523 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20525 * This method is only used by a DataProxy which has retrieved data from a remote server.
20526 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20527 * to contain a method called 'responseXML' that returns an XML document object.
20528 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20529 * a cache of Roo.data.Records.
20531 read : function(response){
20532 var doc = response.responseXML;
20534 throw {message: "XmlReader.read: XML Document not available"};
20536 return this.readRecords(doc);
20540 * Create a data block containing Roo.data.Records from an XML document.
20541 * @param {Object} doc A parsed XML document.
20542 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20543 * a cache of Roo.data.Records.
20545 readRecords : function(doc){
20547 * After any data loads/reads, the raw XML Document is available for further custom processing.
20548 * @type XMLDocument
20550 this.xmlData = doc;
20551 var root = doc.documentElement || doc;
20552 var q = Roo.DomQuery;
20553 var recordType = this.recordType, fields = recordType.prototype.fields;
20554 var sid = this.meta.id;
20555 var totalRecords = 0, success = true;
20556 if(this.meta.totalRecords){
20557 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20560 if(this.meta.success){
20561 var sv = q.selectValue(this.meta.success, root, true);
20562 success = sv !== false && sv !== 'false';
20565 var ns = q.select(this.meta.record, root);
20566 for(var i = 0, len = ns.length; i < len; i++) {
20569 var id = sid ? q.selectValue(sid, n) : undefined;
20570 for(var j = 0, jlen = fields.length; j < jlen; j++){
20571 var f = fields.items[j];
20572 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20574 values[f.name] = v;
20576 var record = new recordType(values, id);
20578 records[records.length] = record;
20584 totalRecords : totalRecords || records.length
20589 * Ext JS Library 1.1.1
20590 * Copyright(c) 2006-2007, Ext JS, LLC.
20592 * Originally Released Under LGPL - original licence link has changed is not relivant.
20595 * <script type="text/javascript">
20599 * @class Roo.data.ArrayReader
20600 * @extends Roo.data.DataReader
20601 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20602 * Each element of that Array represents a row of data fields. The
20603 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20604 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20608 var RecordDef = Roo.data.Record.create([
20609 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20610 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20612 var myReader = new Roo.data.ArrayReader({
20613 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20617 * This would consume an Array like this:
20619 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20621 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20623 * Create a new JsonReader
20624 * @param {Object} meta Metadata configuration options.
20625 * @param {Object} recordType Either an Array of field definition objects
20626 * as specified to {@link Roo.data.Record#create},
20627 * or an {@link Roo.data.Record} object
20628 * created using {@link Roo.data.Record#create}.
20630 Roo.data.ArrayReader = function(meta, recordType){
20631 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20634 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20636 * Create a data block containing Roo.data.Records from an XML document.
20637 * @param {Object} o An Array of row objects which represents the dataset.
20638 * @return {Object} data A data block which is used by an Roo.data.Store object as
20639 * a cache of Roo.data.Records.
20641 readRecords : function(o){
20642 var sid = this.meta ? this.meta.id : null;
20643 var recordType = this.recordType, fields = recordType.prototype.fields;
20646 for(var i = 0; i < root.length; i++){
20649 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20650 for(var j = 0, jlen = fields.length; j < jlen; j++){
20651 var f = fields.items[j];
20652 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20653 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20655 values[f.name] = v;
20657 var record = new recordType(values, id);
20659 records[records.length] = record;
20663 totalRecords : records.length
20668 * Ext JS Library 1.1.1
20669 * Copyright(c) 2006-2007, Ext JS, LLC.
20671 * Originally Released Under LGPL - original licence link has changed is not relivant.
20674 * <script type="text/javascript">
20679 * @class Roo.data.Tree
20680 * @extends Roo.util.Observable
20681 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20682 * in the tree have most standard DOM functionality.
20684 * @param {Node} root (optional) The root node
20686 Roo.data.Tree = function(root){
20687 this.nodeHash = {};
20689 * The root node for this tree
20694 this.setRootNode(root);
20699 * Fires when a new child node is appended to a node in this tree.
20700 * @param {Tree} tree The owner tree
20701 * @param {Node} parent The parent node
20702 * @param {Node} node The newly appended node
20703 * @param {Number} index The index of the newly appended node
20708 * Fires when a child node is removed from a node in this tree.
20709 * @param {Tree} tree The owner tree
20710 * @param {Node} parent The parent node
20711 * @param {Node} node The child node removed
20716 * Fires when a node is moved to a new location in the tree
20717 * @param {Tree} tree The owner tree
20718 * @param {Node} node The node moved
20719 * @param {Node} oldParent The old parent of this node
20720 * @param {Node} newParent The new parent of this node
20721 * @param {Number} index The index it was moved to
20726 * Fires when a new child node is inserted in a node in this tree.
20727 * @param {Tree} tree The owner tree
20728 * @param {Node} parent The parent node
20729 * @param {Node} node The child node inserted
20730 * @param {Node} refNode The child node the node was inserted before
20734 * @event beforeappend
20735 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20736 * @param {Tree} tree The owner tree
20737 * @param {Node} parent The parent node
20738 * @param {Node} node The child node to be appended
20740 "beforeappend" : true,
20742 * @event beforeremove
20743 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20744 * @param {Tree} tree The owner tree
20745 * @param {Node} parent The parent node
20746 * @param {Node} node The child node to be removed
20748 "beforeremove" : true,
20750 * @event beforemove
20751 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20752 * @param {Tree} tree The owner tree
20753 * @param {Node} node The node being moved
20754 * @param {Node} oldParent The parent of the node
20755 * @param {Node} newParent The new parent the node is moving to
20756 * @param {Number} index The index it is being moved to
20758 "beforemove" : true,
20760 * @event beforeinsert
20761 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20762 * @param {Tree} tree The owner tree
20763 * @param {Node} parent The parent node
20764 * @param {Node} node The child node to be inserted
20765 * @param {Node} refNode The child node the node is being inserted before
20767 "beforeinsert" : true
20770 Roo.data.Tree.superclass.constructor.call(this);
20773 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20774 pathSeparator: "/",
20776 proxyNodeEvent : function(){
20777 return this.fireEvent.apply(this, arguments);
20781 * Returns the root node for this tree.
20784 getRootNode : function(){
20789 * Sets the root node for this tree.
20790 * @param {Node} node
20793 setRootNode : function(node){
20795 node.ownerTree = this;
20796 node.isRoot = true;
20797 this.registerNode(node);
20802 * Gets a node in this tree by its id.
20803 * @param {String} id
20806 getNodeById : function(id){
20807 return this.nodeHash[id];
20810 registerNode : function(node){
20811 this.nodeHash[node.id] = node;
20814 unregisterNode : function(node){
20815 delete this.nodeHash[node.id];
20818 toString : function(){
20819 return "[Tree"+(this.id?" "+this.id:"")+"]";
20824 * @class Roo.data.Node
20825 * @extends Roo.util.Observable
20826 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
20827 * @cfg {String} id The id for this node. If one is not specified, one is generated.
20829 * @param {Object} attributes The attributes/config for the node
20831 Roo.data.Node = function(attributes){
20833 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
20836 this.attributes = attributes || {};
20837 this.leaf = this.attributes.leaf;
20839 * The node id. @type String
20841 this.id = this.attributes.id;
20843 this.id = Roo.id(null, "ynode-");
20844 this.attributes.id = this.id;
20847 * All child nodes of this node. @type Array
20849 this.childNodes = [];
20850 if(!this.childNodes.indexOf){ // indexOf is a must
20851 this.childNodes.indexOf = function(o){
20852 for(var i = 0, len = this.length; i < len; i++){
20853 if(this[i] == o) return i;
20859 * The parent node for this node. @type Node
20861 this.parentNode = null;
20863 * The first direct child node of this node, or null if this node has no child nodes. @type Node
20865 this.firstChild = null;
20867 * The last direct child node of this node, or null if this node has no child nodes. @type Node
20869 this.lastChild = null;
20871 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
20873 this.previousSibling = null;
20875 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
20877 this.nextSibling = null;
20882 * Fires when a new child node is appended
20883 * @param {Tree} tree The owner tree
20884 * @param {Node} this This node
20885 * @param {Node} node The newly appended node
20886 * @param {Number} index The index of the newly appended node
20891 * Fires when a child node is removed
20892 * @param {Tree} tree The owner tree
20893 * @param {Node} this This node
20894 * @param {Node} node The removed node
20899 * Fires when this node is moved to a new location in the tree
20900 * @param {Tree} tree The owner tree
20901 * @param {Node} this This node
20902 * @param {Node} oldParent The old parent of this node
20903 * @param {Node} newParent The new parent of this node
20904 * @param {Number} index The index it was moved to
20909 * Fires when a new child node is inserted.
20910 * @param {Tree} tree The owner tree
20911 * @param {Node} this This node
20912 * @param {Node} node The child node inserted
20913 * @param {Node} refNode The child node the node was inserted before
20917 * @event beforeappend
20918 * Fires before a new child is appended, return false to cancel the append.
20919 * @param {Tree} tree The owner tree
20920 * @param {Node} this This node
20921 * @param {Node} node The child node to be appended
20923 "beforeappend" : true,
20925 * @event beforeremove
20926 * Fires before a child is removed, return false to cancel the remove.
20927 * @param {Tree} tree The owner tree
20928 * @param {Node} this This node
20929 * @param {Node} node The child node to be removed
20931 "beforeremove" : true,
20933 * @event beforemove
20934 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
20935 * @param {Tree} tree The owner tree
20936 * @param {Node} this This node
20937 * @param {Node} oldParent The parent of this node
20938 * @param {Node} newParent The new parent this node is moving to
20939 * @param {Number} index The index it is being moved to
20941 "beforemove" : true,
20943 * @event beforeinsert
20944 * Fires before a new child is inserted, return false to cancel the insert.
20945 * @param {Tree} tree The owner tree
20946 * @param {Node} this This node
20947 * @param {Node} node The child node to be inserted
20948 * @param {Node} refNode The child node the node is being inserted before
20950 "beforeinsert" : true
20952 this.listeners = this.attributes.listeners;
20953 Roo.data.Node.superclass.constructor.call(this);
20956 Roo.extend(Roo.data.Node, Roo.util.Observable, {
20957 fireEvent : function(evtName){
20958 // first do standard event for this node
20959 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
20962 // then bubble it up to the tree if the event wasn't cancelled
20963 var ot = this.getOwnerTree();
20965 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
20973 * Returns true if this node is a leaf
20974 * @return {Boolean}
20976 isLeaf : function(){
20977 return this.leaf === true;
20981 setFirstChild : function(node){
20982 this.firstChild = node;
20986 setLastChild : function(node){
20987 this.lastChild = node;
20992 * Returns true if this node is the last child of its parent
20993 * @return {Boolean}
20995 isLast : function(){
20996 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21000 * Returns true if this node is the first child of its parent
21001 * @return {Boolean}
21003 isFirst : function(){
21004 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21007 hasChildNodes : function(){
21008 return !this.isLeaf() && this.childNodes.length > 0;
21012 * Insert node(s) as the last child node of this node.
21013 * @param {Node/Array} node The node or Array of nodes to append
21014 * @return {Node} The appended node if single append, or null if an array was passed
21016 appendChild : function(node){
21018 if(node instanceof Array){
21020 }else if(arguments.length > 1){
21023 // if passed an array or multiple args do them one by one
21025 for(var i = 0, len = multi.length; i < len; i++) {
21026 this.appendChild(multi[i]);
21029 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21032 var index = this.childNodes.length;
21033 var oldParent = node.parentNode;
21034 // it's a move, make sure we move it cleanly
21036 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21039 oldParent.removeChild(node);
21041 index = this.childNodes.length;
21043 this.setFirstChild(node);
21045 this.childNodes.push(node);
21046 node.parentNode = this;
21047 var ps = this.childNodes[index-1];
21049 node.previousSibling = ps;
21050 ps.nextSibling = node;
21052 node.previousSibling = null;
21054 node.nextSibling = null;
21055 this.setLastChild(node);
21056 node.setOwnerTree(this.getOwnerTree());
21057 this.fireEvent("append", this.ownerTree, this, node, index);
21059 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21066 * Removes a child node from this node.
21067 * @param {Node} node The node to remove
21068 * @return {Node} The removed node
21070 removeChild : function(node){
21071 var index = this.childNodes.indexOf(node);
21075 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21079 // remove it from childNodes collection
21080 this.childNodes.splice(index, 1);
21083 if(node.previousSibling){
21084 node.previousSibling.nextSibling = node.nextSibling;
21086 if(node.nextSibling){
21087 node.nextSibling.previousSibling = node.previousSibling;
21090 // update child refs
21091 if(this.firstChild == node){
21092 this.setFirstChild(node.nextSibling);
21094 if(this.lastChild == node){
21095 this.setLastChild(node.previousSibling);
21098 node.setOwnerTree(null);
21099 // clear any references from the node
21100 node.parentNode = null;
21101 node.previousSibling = null;
21102 node.nextSibling = null;
21103 this.fireEvent("remove", this.ownerTree, this, node);
21108 * Inserts the first node before the second node in this nodes childNodes collection.
21109 * @param {Node} node The node to insert
21110 * @param {Node} refNode The node to insert before (if null the node is appended)
21111 * @return {Node} The inserted node
21113 insertBefore : function(node, refNode){
21114 if(!refNode){ // like standard Dom, refNode can be null for append
21115 return this.appendChild(node);
21118 if(node == refNode){
21122 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21125 var index = this.childNodes.indexOf(refNode);
21126 var oldParent = node.parentNode;
21127 var refIndex = index;
21129 // when moving internally, indexes will change after remove
21130 if(oldParent == this && this.childNodes.indexOf(node) < index){
21134 // it's a move, make sure we move it cleanly
21136 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21139 oldParent.removeChild(node);
21142 this.setFirstChild(node);
21144 this.childNodes.splice(refIndex, 0, node);
21145 node.parentNode = this;
21146 var ps = this.childNodes[refIndex-1];
21148 node.previousSibling = ps;
21149 ps.nextSibling = node;
21151 node.previousSibling = null;
21153 node.nextSibling = refNode;
21154 refNode.previousSibling = node;
21155 node.setOwnerTree(this.getOwnerTree());
21156 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21158 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21164 * Returns the child node at the specified index.
21165 * @param {Number} index
21168 item : function(index){
21169 return this.childNodes[index];
21173 * Replaces one child node in this node with another.
21174 * @param {Node} newChild The replacement node
21175 * @param {Node} oldChild The node to replace
21176 * @return {Node} The replaced node
21178 replaceChild : function(newChild, oldChild){
21179 this.insertBefore(newChild, oldChild);
21180 this.removeChild(oldChild);
21185 * Returns the index of a child node
21186 * @param {Node} node
21187 * @return {Number} The index of the node or -1 if it was not found
21189 indexOf : function(child){
21190 return this.childNodes.indexOf(child);
21194 * Returns the tree this node is in.
21197 getOwnerTree : function(){
21198 // if it doesn't have one, look for one
21199 if(!this.ownerTree){
21203 this.ownerTree = p.ownerTree;
21209 return this.ownerTree;
21213 * Returns depth of this node (the root node has a depth of 0)
21216 getDepth : function(){
21219 while(p.parentNode){
21227 setOwnerTree : function(tree){
21228 // if it's move, we need to update everyone
21229 if(tree != this.ownerTree){
21230 if(this.ownerTree){
21231 this.ownerTree.unregisterNode(this);
21233 this.ownerTree = tree;
21234 var cs = this.childNodes;
21235 for(var i = 0, len = cs.length; i < len; i++) {
21236 cs[i].setOwnerTree(tree);
21239 tree.registerNode(this);
21245 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21246 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21247 * @return {String} The path
21249 getPath : function(attr){
21250 attr = attr || "id";
21251 var p = this.parentNode;
21252 var b = [this.attributes[attr]];
21254 b.unshift(p.attributes[attr]);
21257 var sep = this.getOwnerTree().pathSeparator;
21258 return sep + b.join(sep);
21262 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21263 * function call will be the scope provided or the current node. The arguments to the function
21264 * will be the args provided or the current node. If the function returns false at any point,
21265 * the bubble is stopped.
21266 * @param {Function} fn The function to call
21267 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21268 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21270 bubble : function(fn, scope, args){
21273 if(fn.call(scope || p, args || p) === false){
21281 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21282 * function call will be the scope provided or the current node. The arguments to the function
21283 * will be the args provided or the current node. If the function returns false at any point,
21284 * the cascade is stopped on that branch.
21285 * @param {Function} fn The function to call
21286 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21287 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21289 cascade : function(fn, scope, args){
21290 if(fn.call(scope || this, args || this) !== false){
21291 var cs = this.childNodes;
21292 for(var i = 0, len = cs.length; i < len; i++) {
21293 cs[i].cascade(fn, scope, args);
21299 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21300 * function call will be the scope provided or the current node. The arguments to the function
21301 * will be the args provided or the current node. If the function returns false at any point,
21302 * the iteration stops.
21303 * @param {Function} fn The function to call
21304 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21305 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21307 eachChild : function(fn, scope, args){
21308 var cs = this.childNodes;
21309 for(var i = 0, len = cs.length; i < len; i++) {
21310 if(fn.call(scope || this, args || cs[i]) === false){
21317 * Finds the first child that has the attribute with the specified value.
21318 * @param {String} attribute The attribute name
21319 * @param {Mixed} value The value to search for
21320 * @return {Node} The found child or null if none was found
21322 findChild : function(attribute, value){
21323 var cs = this.childNodes;
21324 for(var i = 0, len = cs.length; i < len; i++) {
21325 if(cs[i].attributes[attribute] == value){
21333 * Finds the first child by a custom function. The child matches if the function passed
21335 * @param {Function} fn
21336 * @param {Object} scope (optional)
21337 * @return {Node} The found child or null if none was found
21339 findChildBy : function(fn, scope){
21340 var cs = this.childNodes;
21341 for(var i = 0, len = cs.length; i < len; i++) {
21342 if(fn.call(scope||cs[i], cs[i]) === true){
21350 * Sorts this nodes children using the supplied sort function
21351 * @param {Function} fn
21352 * @param {Object} scope (optional)
21354 sort : function(fn, scope){
21355 var cs = this.childNodes;
21356 var len = cs.length;
21358 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21360 for(var i = 0; i < len; i++){
21362 n.previousSibling = cs[i-1];
21363 n.nextSibling = cs[i+1];
21365 this.setFirstChild(n);
21368 this.setLastChild(n);
21375 * Returns true if this node is an ancestor (at any point) of the passed node.
21376 * @param {Node} node
21377 * @return {Boolean}
21379 contains : function(node){
21380 return node.isAncestor(this);
21384 * Returns true if the passed node is an ancestor (at any point) of this node.
21385 * @param {Node} node
21386 * @return {Boolean}
21388 isAncestor : function(node){
21389 var p = this.parentNode;
21399 toString : function(){
21400 return "[Node"+(this.id?" "+this.id:"")+"]";
21404 * Ext JS Library 1.1.1
21405 * Copyright(c) 2006-2007, Ext JS, LLC.
21407 * Originally Released Under LGPL - original licence link has changed is not relivant.
21410 * <script type="text/javascript">
21415 * @class Roo.ComponentMgr
21416 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21419 Roo.ComponentMgr = function(){
21420 var all = new Roo.util.MixedCollection();
21424 * Registers a component.
21425 * @param {Roo.Component} c The component
21427 register : function(c){
21432 * Unregisters a component.
21433 * @param {Roo.Component} c The component
21435 unregister : function(c){
21440 * Returns a component by id
21441 * @param {String} id The component id
21443 get : function(id){
21444 return all.get(id);
21448 * Registers a function that will be called when a specified component is added to ComponentMgr
21449 * @param {String} id The component id
21450 * @param {Funtction} fn The callback function
21451 * @param {Object} scope The scope of the callback
21453 onAvailable : function(id, fn, scope){
21454 all.on("add", function(index, o){
21456 fn.call(scope || o, o);
21457 all.un("add", fn, scope);
21464 * Ext JS Library 1.1.1
21465 * Copyright(c) 2006-2007, Ext JS, LLC.
21467 * Originally Released Under LGPL - original licence link has changed is not relivant.
21470 * <script type="text/javascript">
21474 * @class Roo.Component
21475 * @extends Roo.util.Observable
21476 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21477 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21478 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21479 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21480 * All visual components (widgets) that require rendering into a layout should subclass Component.
21482 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21483 * 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
21484 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21486 Roo.Component = function(config){
21487 config = config || {};
21488 if(config.tagName || config.dom || typeof config == "string"){ // element object
21489 config = {el: config, id: config.id || config};
21491 this.initialConfig = config;
21493 Roo.apply(this, config);
21497 * Fires after the component is disabled.
21498 * @param {Roo.Component} this
21503 * Fires after the component is enabled.
21504 * @param {Roo.Component} this
21508 * @event beforeshow
21509 * Fires before the component is shown. Return false to stop the show.
21510 * @param {Roo.Component} this
21515 * Fires after the component is shown.
21516 * @param {Roo.Component} this
21520 * @event beforehide
21521 * Fires before the component is hidden. Return false to stop the hide.
21522 * @param {Roo.Component} this
21527 * Fires after the component is hidden.
21528 * @param {Roo.Component} this
21532 * @event beforerender
21533 * Fires before the component is rendered. Return false to stop the render.
21534 * @param {Roo.Component} this
21536 beforerender : true,
21539 * Fires after the component is rendered.
21540 * @param {Roo.Component} this
21544 * @event beforedestroy
21545 * Fires before the component is destroyed. Return false to stop the destroy.
21546 * @param {Roo.Component} this
21548 beforedestroy : true,
21551 * Fires after the component is destroyed.
21552 * @param {Roo.Component} this
21557 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21559 Roo.ComponentMgr.register(this);
21560 Roo.Component.superclass.constructor.call(this);
21561 this.initComponent();
21562 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21563 this.render(this.renderTo);
21564 delete this.renderTo;
21569 Roo.Component.AUTO_ID = 1000;
21571 Roo.extend(Roo.Component, Roo.util.Observable, {
21573 * @property {Boolean} hidden
21574 * true if this component is hidden. Read-only.
21578 * true if this component is disabled. Read-only.
21582 * true if this component has been rendered. Read-only.
21586 /** @cfg {String} disableClass
21587 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21589 disabledClass : "x-item-disabled",
21590 /** @cfg {Boolean} allowDomMove
21591 * Whether the component can move the Dom node when rendering (defaults to true).
21593 allowDomMove : true,
21594 /** @cfg {String} hideMode
21595 * How this component should hidden. Supported values are
21596 * "visibility" (css visibility), "offsets" (negative offset position) and
21597 * "display" (css display) - defaults to "display".
21599 hideMode: 'display',
21602 ctype : "Roo.Component",
21604 /** @cfg {String} actionMode
21605 * which property holds the element that used for hide() / show() / disable() / enable()
21611 getActionEl : function(){
21612 return this[this.actionMode];
21615 initComponent : Roo.emptyFn,
21617 * If this is a lazy rendering component, render it to its container element.
21618 * @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.
21620 render : function(container, position){
21621 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21622 if(!container && this.el){
21623 this.el = Roo.get(this.el);
21624 container = this.el.dom.parentNode;
21625 this.allowDomMove = false;
21627 this.container = Roo.get(container);
21628 this.rendered = true;
21629 if(position !== undefined){
21630 if(typeof position == 'number'){
21631 position = this.container.dom.childNodes[position];
21633 position = Roo.getDom(position);
21636 this.onRender(this.container, position || null);
21638 this.el.addClass(this.cls);
21642 this.el.applyStyles(this.style);
21645 this.fireEvent("render", this);
21646 this.afterRender(this.container);
21658 // default function is not really useful
21659 onRender : function(ct, position){
21661 this.el = Roo.get(this.el);
21662 if(this.allowDomMove !== false){
21663 ct.dom.insertBefore(this.el.dom, position);
21669 getAutoCreate : function(){
21670 var cfg = typeof this.autoCreate == "object" ?
21671 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21672 if(this.id && !cfg.id){
21679 afterRender : Roo.emptyFn,
21682 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21683 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21685 destroy : function(){
21686 if(this.fireEvent("beforedestroy", this) !== false){
21687 this.purgeListeners();
21688 this.beforeDestroy();
21690 this.el.removeAllListeners();
21692 if(this.actionMode == "container"){
21693 this.container.remove();
21697 Roo.ComponentMgr.unregister(this);
21698 this.fireEvent("destroy", this);
21703 beforeDestroy : function(){
21708 onDestroy : function(){
21713 * Returns the underlying {@link Roo.Element}.
21714 * @return {Roo.Element} The element
21716 getEl : function(){
21721 * Returns the id of this component.
21724 getId : function(){
21729 * Try to focus this component.
21730 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21731 * @return {Roo.Component} this
21733 focus : function(selectText){
21736 if(selectText === true){
21737 this.el.dom.select();
21752 * Disable this component.
21753 * @return {Roo.Component} this
21755 disable : function(){
21759 this.disabled = true;
21760 this.fireEvent("disable", this);
21765 onDisable : function(){
21766 this.getActionEl().addClass(this.disabledClass);
21767 this.el.dom.disabled = true;
21771 * Enable this component.
21772 * @return {Roo.Component} this
21774 enable : function(){
21778 this.disabled = false;
21779 this.fireEvent("enable", this);
21784 onEnable : function(){
21785 this.getActionEl().removeClass(this.disabledClass);
21786 this.el.dom.disabled = false;
21790 * Convenience function for setting disabled/enabled by boolean.
21791 * @param {Boolean} disabled
21793 setDisabled : function(disabled){
21794 this[disabled ? "disable" : "enable"]();
21798 * Show this component.
21799 * @return {Roo.Component} this
21802 if(this.fireEvent("beforeshow", this) !== false){
21803 this.hidden = false;
21807 this.fireEvent("show", this);
21813 onShow : function(){
21814 var ae = this.getActionEl();
21815 if(this.hideMode == 'visibility'){
21816 ae.dom.style.visibility = "visible";
21817 }else if(this.hideMode == 'offsets'){
21818 ae.removeClass('x-hidden');
21820 ae.dom.style.display = "";
21825 * Hide this component.
21826 * @return {Roo.Component} this
21829 if(this.fireEvent("beforehide", this) !== false){
21830 this.hidden = true;
21834 this.fireEvent("hide", this);
21840 onHide : function(){
21841 var ae = this.getActionEl();
21842 if(this.hideMode == 'visibility'){
21843 ae.dom.style.visibility = "hidden";
21844 }else if(this.hideMode == 'offsets'){
21845 ae.addClass('x-hidden');
21847 ae.dom.style.display = "none";
21852 * Convenience function to hide or show this component by boolean.
21853 * @param {Boolean} visible True to show, false to hide
21854 * @return {Roo.Component} this
21856 setVisible: function(visible){
21866 * Returns true if this component is visible.
21868 isVisible : function(){
21869 return this.getActionEl().isVisible();
21872 cloneConfig : function(overrides){
21873 overrides = overrides || {};
21874 var id = overrides.id || Roo.id();
21875 var cfg = Roo.applyIf(overrides, this.initialConfig);
21876 cfg.id = id; // prevent dup id
21877 return new this.constructor(cfg);
21881 * Ext JS Library 1.1.1
21882 * Copyright(c) 2006-2007, Ext JS, LLC.
21884 * Originally Released Under LGPL - original licence link has changed is not relivant.
21887 * <script type="text/javascript">
21892 * @extends Roo.Element
21893 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
21894 * automatic maintaining of shadow/shim positions.
21895 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
21896 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
21897 * you can pass a string with a CSS class name. False turns off the shadow.
21898 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
21899 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
21900 * @cfg {String} cls CSS class to add to the element
21901 * @cfg {Number} zindex Starting z-index (defaults to 11000)
21902 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
21904 * @param {Object} config An object with config options.
21905 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
21908 Roo.Layer = function(config, existingEl){
21909 config = config || {};
21910 var dh = Roo.DomHelper;
21911 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
21913 this.dom = Roo.getDom(existingEl);
21916 var o = config.dh || {tag: "div", cls: "x-layer"};
21917 this.dom = dh.append(pel, o);
21920 this.addClass(config.cls);
21922 this.constrain = config.constrain !== false;
21923 this.visibilityMode = Roo.Element.VISIBILITY;
21925 this.id = this.dom.id = config.id;
21927 this.id = Roo.id(this.dom);
21929 this.zindex = config.zindex || this.getZIndex();
21930 this.position("absolute", this.zindex);
21932 this.shadowOffset = config.shadowOffset || 4;
21933 this.shadow = new Roo.Shadow({
21934 offset : this.shadowOffset,
21935 mode : config.shadow
21938 this.shadowOffset = 0;
21940 this.useShim = config.shim !== false && Roo.useShims;
21941 this.useDisplay = config.useDisplay;
21945 var supr = Roo.Element.prototype;
21947 // shims are shared among layer to keep from having 100 iframes
21950 Roo.extend(Roo.Layer, Roo.Element, {
21952 getZIndex : function(){
21953 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
21956 getShim : function(){
21963 var shim = shims.shift();
21965 shim = this.createShim();
21966 shim.enableDisplayMode('block');
21967 shim.dom.style.display = 'none';
21968 shim.dom.style.visibility = 'visible';
21970 var pn = this.dom.parentNode;
21971 if(shim.dom.parentNode != pn){
21972 pn.insertBefore(shim.dom, this.dom);
21974 shim.setStyle('z-index', this.getZIndex()-2);
21979 hideShim : function(){
21981 this.shim.setDisplayed(false);
21982 shims.push(this.shim);
21987 disableShadow : function(){
21989 this.shadowDisabled = true;
21990 this.shadow.hide();
21991 this.lastShadowOffset = this.shadowOffset;
21992 this.shadowOffset = 0;
21996 enableShadow : function(show){
21998 this.shadowDisabled = false;
21999 this.shadowOffset = this.lastShadowOffset;
22000 delete this.lastShadowOffset;
22008 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22009 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22010 sync : function(doShow){
22011 var sw = this.shadow;
22012 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22013 var sh = this.getShim();
22015 var w = this.getWidth(),
22016 h = this.getHeight();
22018 var l = this.getLeft(true),
22019 t = this.getTop(true);
22021 if(sw && !this.shadowDisabled){
22022 if(doShow && !sw.isVisible()){
22025 sw.realign(l, t, w, h);
22031 // fit the shim behind the shadow, so it is shimmed too
22032 var a = sw.adjusts, s = sh.dom.style;
22033 s.left = (Math.min(l, l+a.l))+"px";
22034 s.top = (Math.min(t, t+a.t))+"px";
22035 s.width = (w+a.w)+"px";
22036 s.height = (h+a.h)+"px";
22043 sh.setLeftTop(l, t);
22050 destroy : function(){
22053 this.shadow.hide();
22055 this.removeAllListeners();
22056 var pn = this.dom.parentNode;
22058 pn.removeChild(this.dom);
22060 Roo.Element.uncache(this.id);
22063 remove : function(){
22068 beginUpdate : function(){
22069 this.updating = true;
22073 endUpdate : function(){
22074 this.updating = false;
22079 hideUnders : function(negOffset){
22081 this.shadow.hide();
22087 constrainXY : function(){
22088 if(this.constrain){
22089 var vw = Roo.lib.Dom.getViewWidth(),
22090 vh = Roo.lib.Dom.getViewHeight();
22091 var s = Roo.get(document).getScroll();
22093 var xy = this.getXY();
22094 var x = xy[0], y = xy[1];
22095 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22096 // only move it if it needs it
22098 // first validate right/bottom
22099 if((x + w) > vw+s.left){
22100 x = vw - w - this.shadowOffset;
22103 if((y + h) > vh+s.top){
22104 y = vh - h - this.shadowOffset;
22107 // then make sure top/left isn't negative
22118 var ay = this.avoidY;
22119 if(y <= ay && (y+h) >= ay){
22125 supr.setXY.call(this, xy);
22131 isVisible : function(){
22132 return this.visible;
22136 showAction : function(){
22137 this.visible = true; // track visibility to prevent getStyle calls
22138 if(this.useDisplay === true){
22139 this.setDisplayed("");
22140 }else if(this.lastXY){
22141 supr.setXY.call(this, this.lastXY);
22142 }else if(this.lastLT){
22143 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22148 hideAction : function(){
22149 this.visible = false;
22150 if(this.useDisplay === true){
22151 this.setDisplayed(false);
22153 this.setLeftTop(-10000,-10000);
22157 // overridden Element method
22158 setVisible : function(v, a, d, c, e){
22163 var cb = function(){
22168 }.createDelegate(this);
22169 supr.setVisible.call(this, true, true, d, cb, e);
22172 this.hideUnders(true);
22181 }.createDelegate(this);
22183 supr.setVisible.call(this, v, a, d, cb, e);
22192 storeXY : function(xy){
22193 delete this.lastLT;
22197 storeLeftTop : function(left, top){
22198 delete this.lastXY;
22199 this.lastLT = [left, top];
22203 beforeFx : function(){
22204 this.beforeAction();
22205 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22209 afterFx : function(){
22210 Roo.Layer.superclass.afterFx.apply(this, arguments);
22211 this.sync(this.isVisible());
22215 beforeAction : function(){
22216 if(!this.updating && this.shadow){
22217 this.shadow.hide();
22221 // overridden Element method
22222 setLeft : function(left){
22223 this.storeLeftTop(left, this.getTop(true));
22224 supr.setLeft.apply(this, arguments);
22228 setTop : function(top){
22229 this.storeLeftTop(this.getLeft(true), top);
22230 supr.setTop.apply(this, arguments);
22234 setLeftTop : function(left, top){
22235 this.storeLeftTop(left, top);
22236 supr.setLeftTop.apply(this, arguments);
22240 setXY : function(xy, a, d, c, e){
22242 this.beforeAction();
22244 var cb = this.createCB(c);
22245 supr.setXY.call(this, xy, a, d, cb, e);
22252 createCB : function(c){
22263 // overridden Element method
22264 setX : function(x, a, d, c, e){
22265 this.setXY([x, this.getY()], a, d, c, e);
22268 // overridden Element method
22269 setY : function(y, a, d, c, e){
22270 this.setXY([this.getX(), y], a, d, c, e);
22273 // overridden Element method
22274 setSize : function(w, h, a, d, c, e){
22275 this.beforeAction();
22276 var cb = this.createCB(c);
22277 supr.setSize.call(this, w, h, a, d, cb, e);
22283 // overridden Element method
22284 setWidth : function(w, a, d, c, e){
22285 this.beforeAction();
22286 var cb = this.createCB(c);
22287 supr.setWidth.call(this, w, a, d, cb, e);
22293 // overridden Element method
22294 setHeight : function(h, a, d, c, e){
22295 this.beforeAction();
22296 var cb = this.createCB(c);
22297 supr.setHeight.call(this, h, a, d, cb, e);
22303 // overridden Element method
22304 setBounds : function(x, y, w, h, a, d, c, e){
22305 this.beforeAction();
22306 var cb = this.createCB(c);
22308 this.storeXY([x, y]);
22309 supr.setXY.call(this, [x, y]);
22310 supr.setSize.call(this, w, h, a, d, cb, e);
22313 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22319 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22320 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22321 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22322 * @param {Number} zindex The new z-index to set
22323 * @return {this} The Layer
22325 setZIndex : function(zindex){
22326 this.zindex = zindex;
22327 this.setStyle("z-index", zindex + 2);
22329 this.shadow.setZIndex(zindex + 1);
22332 this.shim.setStyle("z-index", zindex);
22338 * Ext JS Library 1.1.1
22339 * Copyright(c) 2006-2007, Ext JS, LLC.
22341 * Originally Released Under LGPL - original licence link has changed is not relivant.
22344 * <script type="text/javascript">
22349 * @class Roo.Shadow
22350 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22351 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22352 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22354 * Create a new Shadow
22355 * @param {Object} config The config object
22357 Roo.Shadow = function(config){
22358 Roo.apply(this, config);
22359 if(typeof this.mode != "string"){
22360 this.mode = this.defaultMode;
22362 var o = this.offset, a = {h: 0};
22363 var rad = Math.floor(this.offset/2);
22364 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22370 a.l -= this.offset + rad;
22371 a.t -= this.offset + rad;
22382 a.l -= (this.offset - rad);
22383 a.t -= this.offset + rad;
22385 a.w -= (this.offset - rad)*2;
22396 a.l -= (this.offset - rad);
22397 a.t -= (this.offset - rad);
22399 a.w -= (this.offset + rad + 1);
22400 a.h -= (this.offset + rad);
22409 Roo.Shadow.prototype = {
22411 * @cfg {String} mode
22412 * The shadow display mode. Supports the following options:<br />
22413 * sides: Shadow displays on both sides and bottom only<br />
22414 * frame: Shadow displays equally on all four sides<br />
22415 * drop: Traditional bottom-right drop shadow (default)
22418 * @cfg {String} offset
22419 * The number of pixels to offset the shadow from the element (defaults to 4)
22424 defaultMode: "drop",
22427 * Displays the shadow under the target element
22428 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22430 show : function(target){
22431 target = Roo.get(target);
22433 this.el = Roo.Shadow.Pool.pull();
22434 if(this.el.dom.nextSibling != target.dom){
22435 this.el.insertBefore(target);
22438 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22440 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22443 target.getLeft(true),
22444 target.getTop(true),
22448 this.el.dom.style.display = "block";
22452 * Returns true if the shadow is visible, else false
22454 isVisible : function(){
22455 return this.el ? true : false;
22459 * Direct alignment when values are already available. Show must be called at least once before
22460 * calling this method to ensure it is initialized.
22461 * @param {Number} left The target element left position
22462 * @param {Number} top The target element top position
22463 * @param {Number} width The target element width
22464 * @param {Number} height The target element height
22466 realign : function(l, t, w, h){
22470 var a = this.adjusts, d = this.el.dom, s = d.style;
22472 s.left = (l+a.l)+"px";
22473 s.top = (t+a.t)+"px";
22474 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22475 if(s.width != sws || s.height != shs){
22479 var cn = d.childNodes;
22480 var sww = Math.max(0, (sw-12))+"px";
22481 cn[0].childNodes[1].style.width = sww;
22482 cn[1].childNodes[1].style.width = sww;
22483 cn[2].childNodes[1].style.width = sww;
22484 cn[1].style.height = Math.max(0, (sh-12))+"px";
22490 * Hides this shadow
22494 this.el.dom.style.display = "none";
22495 Roo.Shadow.Pool.push(this.el);
22501 * Adjust the z-index of this shadow
22502 * @param {Number} zindex The new z-index
22504 setZIndex : function(z){
22507 this.el.setStyle("z-index", z);
22512 // Private utility class that manages the internal Shadow cache
22513 Roo.Shadow.Pool = function(){
22515 var markup = Roo.isIE ?
22516 '<div class="x-ie-shadow"></div>' :
22517 '<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>';
22520 var sh = p.shift();
22522 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22523 sh.autoBoxAdjust = false;
22528 push : function(sh){
22534 * Ext JS Library 1.1.1
22535 * Copyright(c) 2006-2007, Ext JS, LLC.
22537 * Originally Released Under LGPL - original licence link has changed is not relivant.
22540 * <script type="text/javascript">
22544 * @class Roo.BoxComponent
22545 * @extends Roo.Component
22546 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22547 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22548 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22549 * layout containers.
22551 * @param {Roo.Element/String/Object} config The configuration options.
22553 Roo.BoxComponent = function(config){
22554 Roo.Component.call(this, config);
22558 * Fires after the component is resized.
22559 * @param {Roo.Component} this
22560 * @param {Number} adjWidth The box-adjusted width that was set
22561 * @param {Number} adjHeight The box-adjusted height that was set
22562 * @param {Number} rawWidth The width that was originally specified
22563 * @param {Number} rawHeight The height that was originally specified
22568 * Fires after the component is moved.
22569 * @param {Roo.Component} this
22570 * @param {Number} x The new x position
22571 * @param {Number} y The new y position
22577 Roo.extend(Roo.BoxComponent, Roo.Component, {
22578 // private, set in afterRender to signify that the component has been rendered
22580 // private, used to defer height settings to subclasses
22581 deferHeight: false,
22582 /** @cfg {Number} width
22583 * width (optional) size of component
22585 /** @cfg {Number} height
22586 * height (optional) size of component
22590 * Sets the width and height of the component. This method fires the resize event. This method can accept
22591 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22592 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22593 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22594 * @return {Roo.BoxComponent} this
22596 setSize : function(w, h){
22597 // support for standard size objects
22598 if(typeof w == 'object'){
22603 if(!this.boxReady){
22609 // prevent recalcs when not needed
22610 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22613 this.lastSize = {width: w, height: h};
22615 var adj = this.adjustSize(w, h);
22616 var aw = adj.width, ah = adj.height;
22617 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22618 var rz = this.getResizeEl();
22619 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22620 rz.setSize(aw, ah);
22621 }else if(!this.deferHeight && ah !== undefined){
22623 }else if(aw !== undefined){
22626 this.onResize(aw, ah, w, h);
22627 this.fireEvent('resize', this, aw, ah, w, h);
22633 * Gets the current size of the component's underlying element.
22634 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22636 getSize : function(){
22637 return this.el.getSize();
22641 * Gets the current XY position of the component's underlying element.
22642 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22643 * @return {Array} The XY position of the element (e.g., [100, 200])
22645 getPosition : function(local){
22646 if(local === true){
22647 return [this.el.getLeft(true), this.el.getTop(true)];
22649 return this.xy || this.el.getXY();
22653 * Gets the current box measurements of the component's underlying element.
22654 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22655 * @returns {Object} box An object in the format {x, y, width, height}
22657 getBox : function(local){
22658 var s = this.el.getSize();
22660 s.x = this.el.getLeft(true);
22661 s.y = this.el.getTop(true);
22663 var xy = this.xy || this.el.getXY();
22671 * Sets the current box measurements of the component's underlying element.
22672 * @param {Object} box An object in the format {x, y, width, height}
22673 * @returns {Roo.BoxComponent} this
22675 updateBox : function(box){
22676 this.setSize(box.width, box.height);
22677 this.setPagePosition(box.x, box.y);
22682 getResizeEl : function(){
22683 return this.resizeEl || this.el;
22687 getPositionEl : function(){
22688 return this.positionEl || this.el;
22692 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22693 * This method fires the move event.
22694 * @param {Number} left The new left
22695 * @param {Number} top The new top
22696 * @returns {Roo.BoxComponent} this
22698 setPosition : function(x, y){
22701 if(!this.boxReady){
22704 var adj = this.adjustPosition(x, y);
22705 var ax = adj.x, ay = adj.y;
22707 var el = this.getPositionEl();
22708 if(ax !== undefined || ay !== undefined){
22709 if(ax !== undefined && ay !== undefined){
22710 el.setLeftTop(ax, ay);
22711 }else if(ax !== undefined){
22713 }else if(ay !== undefined){
22716 this.onPosition(ax, ay);
22717 this.fireEvent('move', this, ax, ay);
22723 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22724 * This method fires the move event.
22725 * @param {Number} x The new x position
22726 * @param {Number} y The new y position
22727 * @returns {Roo.BoxComponent} this
22729 setPagePosition : function(x, y){
22732 if(!this.boxReady){
22735 if(x === undefined || y === undefined){ // cannot translate undefined points
22738 var p = this.el.translatePoints(x, y);
22739 this.setPosition(p.left, p.top);
22744 onRender : function(ct, position){
22745 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22747 this.resizeEl = Roo.get(this.resizeEl);
22749 if(this.positionEl){
22750 this.positionEl = Roo.get(this.positionEl);
22755 afterRender : function(){
22756 Roo.BoxComponent.superclass.afterRender.call(this);
22757 this.boxReady = true;
22758 this.setSize(this.width, this.height);
22759 if(this.x || this.y){
22760 this.setPosition(this.x, this.y);
22762 if(this.pageX || this.pageY){
22763 this.setPagePosition(this.pageX, this.pageY);
22768 * Force the component's size to recalculate based on the underlying element's current height and width.
22769 * @returns {Roo.BoxComponent} this
22771 syncSize : function(){
22772 delete this.lastSize;
22773 this.setSize(this.el.getWidth(), this.el.getHeight());
22778 * Called after the component is resized, this method is empty by default but can be implemented by any
22779 * subclass that needs to perform custom logic after a resize occurs.
22780 * @param {Number} adjWidth The box-adjusted width that was set
22781 * @param {Number} adjHeight The box-adjusted height that was set
22782 * @param {Number} rawWidth The width that was originally specified
22783 * @param {Number} rawHeight The height that was originally specified
22785 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22790 * Called after the component is moved, this method is empty by default but can be implemented by any
22791 * subclass that needs to perform custom logic after a move occurs.
22792 * @param {Number} x The new x position
22793 * @param {Number} y The new y position
22795 onPosition : function(x, y){
22800 adjustSize : function(w, h){
22801 if(this.autoWidth){
22804 if(this.autoHeight){
22807 return {width : w, height: h};
22811 adjustPosition : function(x, y){
22812 return {x : x, y: y};
22816 * Ext JS Library 1.1.1
22817 * Copyright(c) 2006-2007, Ext JS, LLC.
22819 * Originally Released Under LGPL - original licence link has changed is not relivant.
22822 * <script type="text/javascript">
22827 * @class Roo.SplitBar
22828 * @extends Roo.util.Observable
22829 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
22833 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
22834 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
22835 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
22836 split.minSize = 100;
22837 split.maxSize = 600;
22838 split.animate = true;
22839 split.on('moved', splitterMoved);
22842 * Create a new SplitBar
22843 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
22844 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
22845 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22846 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
22847 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
22848 position of the SplitBar).
22850 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
22853 this.el = Roo.get(dragElement, true);
22854 this.el.dom.unselectable = "on";
22856 this.resizingEl = Roo.get(resizingElement, true);
22860 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22861 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
22864 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
22867 * The minimum size of the resizing element. (Defaults to 0)
22873 * The maximum size of the resizing element. (Defaults to 2000)
22876 this.maxSize = 2000;
22879 * Whether to animate the transition to the new size
22882 this.animate = false;
22885 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
22888 this.useShim = false;
22893 if(!existingProxy){
22895 this.proxy = Roo.SplitBar.createProxy(this.orientation);
22897 this.proxy = Roo.get(existingProxy).dom;
22900 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
22903 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
22906 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
22909 this.dragSpecs = {};
22912 * @private The adapter to use to positon and resize elements
22914 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
22915 this.adapter.init(this);
22917 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22919 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
22920 this.el.addClass("x-splitbar-h");
22923 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
22924 this.el.addClass("x-splitbar-v");
22930 * Fires when the splitter is moved (alias for {@link #event-moved})
22931 * @param {Roo.SplitBar} this
22932 * @param {Number} newSize the new width or height
22937 * Fires when the splitter is moved
22938 * @param {Roo.SplitBar} this
22939 * @param {Number} newSize the new width or height
22943 * @event beforeresize
22944 * Fires before the splitter is dragged
22945 * @param {Roo.SplitBar} this
22947 "beforeresize" : true,
22949 "beforeapply" : true
22952 Roo.util.Observable.call(this);
22955 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
22956 onStartProxyDrag : function(x, y){
22957 this.fireEvent("beforeresize", this);
22959 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
22961 o.enableDisplayMode("block");
22962 // all splitbars share the same overlay
22963 Roo.SplitBar.prototype.overlay = o;
22965 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
22966 this.overlay.show();
22967 Roo.get(this.proxy).setDisplayed("block");
22968 var size = this.adapter.getElementSize(this);
22969 this.activeMinSize = this.getMinimumSize();;
22970 this.activeMaxSize = this.getMaximumSize();;
22971 var c1 = size - this.activeMinSize;
22972 var c2 = Math.max(this.activeMaxSize - size, 0);
22973 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22974 this.dd.resetConstraints();
22975 this.dd.setXConstraint(
22976 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
22977 this.placement == Roo.SplitBar.LEFT ? c2 : c1
22979 this.dd.setYConstraint(0, 0);
22981 this.dd.resetConstraints();
22982 this.dd.setXConstraint(0, 0);
22983 this.dd.setYConstraint(
22984 this.placement == Roo.SplitBar.TOP ? c1 : c2,
22985 this.placement == Roo.SplitBar.TOP ? c2 : c1
22988 this.dragSpecs.startSize = size;
22989 this.dragSpecs.startPoint = [x, y];
22990 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
22994 * @private Called after the drag operation by the DDProxy
22996 onEndProxyDrag : function(e){
22997 Roo.get(this.proxy).setDisplayed(false);
22998 var endPoint = Roo.lib.Event.getXY(e);
23000 this.overlay.hide();
23003 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23004 newSize = this.dragSpecs.startSize +
23005 (this.placement == Roo.SplitBar.LEFT ?
23006 endPoint[0] - this.dragSpecs.startPoint[0] :
23007 this.dragSpecs.startPoint[0] - endPoint[0]
23010 newSize = this.dragSpecs.startSize +
23011 (this.placement == Roo.SplitBar.TOP ?
23012 endPoint[1] - this.dragSpecs.startPoint[1] :
23013 this.dragSpecs.startPoint[1] - endPoint[1]
23016 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23017 if(newSize != this.dragSpecs.startSize){
23018 if(this.fireEvent('beforeapply', this, newSize) !== false){
23019 this.adapter.setElementSize(this, newSize);
23020 this.fireEvent("moved", this, newSize);
23021 this.fireEvent("resize", this, newSize);
23027 * Get the adapter this SplitBar uses
23028 * @return The adapter object
23030 getAdapter : function(){
23031 return this.adapter;
23035 * Set the adapter this SplitBar uses
23036 * @param {Object} adapter A SplitBar adapter object
23038 setAdapter : function(adapter){
23039 this.adapter = adapter;
23040 this.adapter.init(this);
23044 * Gets the minimum size for the resizing element
23045 * @return {Number} The minimum size
23047 getMinimumSize : function(){
23048 return this.minSize;
23052 * Sets the minimum size for the resizing element
23053 * @param {Number} minSize The minimum size
23055 setMinimumSize : function(minSize){
23056 this.minSize = minSize;
23060 * Gets the maximum size for the resizing element
23061 * @return {Number} The maximum size
23063 getMaximumSize : function(){
23064 return this.maxSize;
23068 * Sets the maximum size for the resizing element
23069 * @param {Number} maxSize The maximum size
23071 setMaximumSize : function(maxSize){
23072 this.maxSize = maxSize;
23076 * Sets the initialize size for the resizing element
23077 * @param {Number} size The initial size
23079 setCurrentSize : function(size){
23080 var oldAnimate = this.animate;
23081 this.animate = false;
23082 this.adapter.setElementSize(this, size);
23083 this.animate = oldAnimate;
23087 * Destroy this splitbar.
23088 * @param {Boolean} removeEl True to remove the element
23090 destroy : function(removeEl){
23092 this.shim.remove();
23095 this.proxy.parentNode.removeChild(this.proxy);
23103 * @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.
23105 Roo.SplitBar.createProxy = function(dir){
23106 var proxy = new Roo.Element(document.createElement("div"));
23107 proxy.unselectable();
23108 var cls = 'x-splitbar-proxy';
23109 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23110 document.body.appendChild(proxy.dom);
23115 * @class Roo.SplitBar.BasicLayoutAdapter
23116 * Default Adapter. It assumes the splitter and resizing element are not positioned
23117 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23119 Roo.SplitBar.BasicLayoutAdapter = function(){
23122 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23123 // do nothing for now
23124 init : function(s){
23128 * Called before drag operations to get the current size of the resizing element.
23129 * @param {Roo.SplitBar} s The SplitBar using this adapter
23131 getElementSize : function(s){
23132 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23133 return s.resizingEl.getWidth();
23135 return s.resizingEl.getHeight();
23140 * Called after drag operations to set the size of the resizing element.
23141 * @param {Roo.SplitBar} s The SplitBar using this adapter
23142 * @param {Number} newSize The new size to set
23143 * @param {Function} onComplete A function to be invoked when resizing is complete
23145 setElementSize : function(s, newSize, onComplete){
23146 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23148 s.resizingEl.setWidth(newSize);
23150 onComplete(s, newSize);
23153 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23158 s.resizingEl.setHeight(newSize);
23160 onComplete(s, newSize);
23163 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23170 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23171 * @extends Roo.SplitBar.BasicLayoutAdapter
23172 * Adapter that moves the splitter element to align with the resized sizing element.
23173 * Used with an absolute positioned SplitBar.
23174 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23175 * document.body, make sure you assign an id to the body element.
23177 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23178 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23179 this.container = Roo.get(container);
23182 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23183 init : function(s){
23184 this.basic.init(s);
23187 getElementSize : function(s){
23188 return this.basic.getElementSize(s);
23191 setElementSize : function(s, newSize, onComplete){
23192 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23195 moveSplitter : function(s){
23196 var yes = Roo.SplitBar;
23197 switch(s.placement){
23199 s.el.setX(s.resizingEl.getRight());
23202 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23205 s.el.setY(s.resizingEl.getBottom());
23208 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23215 * Orientation constant - Create a vertical SplitBar
23219 Roo.SplitBar.VERTICAL = 1;
23222 * Orientation constant - Create a horizontal SplitBar
23226 Roo.SplitBar.HORIZONTAL = 2;
23229 * Placement constant - The resizing element is to the left of the splitter element
23233 Roo.SplitBar.LEFT = 1;
23236 * Placement constant - The resizing element is to the right of the splitter element
23240 Roo.SplitBar.RIGHT = 2;
23243 * Placement constant - The resizing element is positioned above the splitter element
23247 Roo.SplitBar.TOP = 3;
23250 * Placement constant - The resizing element is positioned under splitter element
23254 Roo.SplitBar.BOTTOM = 4;
23257 * Ext JS Library 1.1.1
23258 * Copyright(c) 2006-2007, Ext JS, LLC.
23260 * Originally Released Under LGPL - original licence link has changed is not relivant.
23263 * <script type="text/javascript">
23268 * @extends Roo.util.Observable
23269 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23270 * This class also supports single and multi selection modes. <br>
23271 * Create a data model bound view:
23273 var store = new Roo.data.Store(...);
23275 var view = new Roo.View({
23277 template : '<div id="{0}">{2} - {1}</div>', // auto create template
23279 singleSelect: true,
23280 selectedClass: "ydataview-selected",
23284 // listen for node click?
23285 view.on("click", function(vw, index, node, e){
23286 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23290 dataModel.load("foobar.xml");
23292 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23294 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23295 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23297 * Note: old style constructor is still suported (container, template, config)
23300 * Create a new View
23301 * @param {Object} config The config object
23304 Roo.View = function(config, depreciated_tpl, depreciated_config){
23306 if (typeof(depreciated_tpl) == 'undefined') {
23307 // new way.. - universal constructor.
23308 Roo.apply(this, config);
23309 this.el = Roo.get(this.el);
23312 this.el = Roo.get(config);
23313 this.tpl = depreciated_tpl;
23314 Roo.apply(this, depreciated_config);
23318 if(typeof(this.tpl) == "string"){
23319 this.tpl = new Roo.Template(this.tpl);
23323 this.tpl.compile();
23330 * @event beforeclick
23331 * Fires before a click is processed. Returns false to cancel the default action.
23332 * @param {Roo.View} this
23333 * @param {Number} index The index of the target node
23334 * @param {HTMLElement} node The target node
23335 * @param {Roo.EventObject} e The raw event object
23337 "beforeclick" : true,
23340 * Fires when a template node is clicked.
23341 * @param {Roo.View} this
23342 * @param {Number} index The index of the target node
23343 * @param {HTMLElement} node The target node
23344 * @param {Roo.EventObject} e The raw event object
23349 * Fires when a template node is double clicked.
23350 * @param {Roo.View} this
23351 * @param {Number} index The index of the target node
23352 * @param {HTMLElement} node The target node
23353 * @param {Roo.EventObject} e The raw event object
23357 * @event contextmenu
23358 * Fires when a template node is right clicked.
23359 * @param {Roo.View} this
23360 * @param {Number} index The index of the target node
23361 * @param {HTMLElement} node The target node
23362 * @param {Roo.EventObject} e The raw event object
23364 "contextmenu" : true,
23366 * @event selectionchange
23367 * Fires when the selected nodes change.
23368 * @param {Roo.View} this
23369 * @param {Array} selections Array of the selected nodes
23371 "selectionchange" : true,
23374 * @event beforeselect
23375 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23376 * @param {Roo.View} this
23377 * @param {HTMLElement} node The node to be selected
23378 * @param {Array} selections Array of currently selected nodes
23380 "beforeselect" : true
23384 "click": this.onClick,
23385 "dblclick": this.onDblClick,
23386 "contextmenu": this.onContextMenu,
23390 this.selections = [];
23392 this.cmp = new Roo.CompositeElementLite([]);
23394 this.store = Roo.factory(this.store, Roo.data);
23395 this.setStore(this.store, true);
23397 Roo.View.superclass.constructor.call(this);
23400 Roo.extend(Roo.View, Roo.util.Observable, {
23403 * @cfg {Roo.data.Store} store Data store to load data from.
23408 * @cfg {String|Roo.Element} el The container element.
23413 * @cfg {String|Roo.Template} tpl The template used by this View
23418 * @cfg {String} selectedClass The css class to add to selected nodes
23420 selectedClass : "x-view-selected",
23422 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23426 * Returns the element this view is bound to.
23427 * @return {Roo.Element}
23429 getEl : function(){
23434 * Refreshes the view.
23436 refresh : function(){
23438 this.clearSelections();
23439 this.el.update("");
23441 var records = this.store.getRange();
23442 if(records.length < 1){
23443 this.el.update(this.emptyText);
23446 for(var i = 0, len = records.length; i < len; i++){
23447 var data = this.prepareData(records[i].data, i, records[i]);
23448 html[html.length] = t.apply(data);
23450 this.el.update(html.join(""));
23451 this.nodes = this.el.dom.childNodes;
23452 this.updateIndexes(0);
23456 * Function to override to reformat the data that is sent to
23457 * the template for each node.
23458 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23459 * a JSON object for an UpdateManager bound view).
23461 prepareData : function(data){
23465 onUpdate : function(ds, record){
23466 this.clearSelections();
23467 var index = this.store.indexOf(record);
23468 var n = this.nodes[index];
23469 this.tpl.insertBefore(n, this.prepareData(record.data));
23470 n.parentNode.removeChild(n);
23471 this.updateIndexes(index, index);
23474 onAdd : function(ds, records, index){
23475 this.clearSelections();
23476 if(this.nodes.length == 0){
23480 var n = this.nodes[index];
23481 for(var i = 0, len = records.length; i < len; i++){
23482 var d = this.prepareData(records[i].data);
23484 this.tpl.insertBefore(n, d);
23486 this.tpl.append(this.el, d);
23489 this.updateIndexes(index);
23492 onRemove : function(ds, record, index){
23493 this.clearSelections();
23494 this.el.dom.removeChild(this.nodes[index]);
23495 this.updateIndexes(index);
23499 * Refresh an individual node.
23500 * @param {Number} index
23502 refreshNode : function(index){
23503 this.onUpdate(this.store, this.store.getAt(index));
23506 updateIndexes : function(startIndex, endIndex){
23507 var ns = this.nodes;
23508 startIndex = startIndex || 0;
23509 endIndex = endIndex || ns.length - 1;
23510 for(var i = startIndex; i <= endIndex; i++){
23511 ns[i].nodeIndex = i;
23516 * Changes the data store this view uses and refresh the view.
23517 * @param {Store} store
23519 setStore : function(store, initial){
23520 if(!initial && this.store){
23521 this.store.un("datachanged", this.refresh);
23522 this.store.un("add", this.onAdd);
23523 this.store.un("remove", this.onRemove);
23524 this.store.un("update", this.onUpdate);
23525 this.store.un("clear", this.refresh);
23529 store.on("datachanged", this.refresh, this);
23530 store.on("add", this.onAdd, this);
23531 store.on("remove", this.onRemove, this);
23532 store.on("update", this.onUpdate, this);
23533 store.on("clear", this.refresh, this);
23542 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23543 * @param {HTMLElement} node
23544 * @return {HTMLElement} The template node
23546 findItemFromChild : function(node){
23547 var el = this.el.dom;
23548 if(!node || node.parentNode == el){
23551 var p = node.parentNode;
23552 while(p && p != el){
23553 if(p.parentNode == el){
23562 onClick : function(e){
23563 var item = this.findItemFromChild(e.getTarget());
23565 var index = this.indexOf(item);
23566 if(this.onItemClick(item, index, e) !== false){
23567 this.fireEvent("click", this, index, item, e);
23570 this.clearSelections();
23575 onContextMenu : function(e){
23576 var item = this.findItemFromChild(e.getTarget());
23578 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23583 onDblClick : function(e){
23584 var item = this.findItemFromChild(e.getTarget());
23586 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23590 onItemClick : function(item, index, e){
23591 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23594 if(this.multiSelect || this.singleSelect){
23595 if(this.multiSelect && e.shiftKey && this.lastSelection){
23596 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23598 this.select(item, this.multiSelect && e.ctrlKey);
23599 this.lastSelection = item;
23601 e.preventDefault();
23607 * Get the number of selected nodes.
23610 getSelectionCount : function(){
23611 return this.selections.length;
23615 * Get the currently selected nodes.
23616 * @return {Array} An array of HTMLElements
23618 getSelectedNodes : function(){
23619 return this.selections;
23623 * Get the indexes of the selected nodes.
23626 getSelectedIndexes : function(){
23627 var indexes = [], s = this.selections;
23628 for(var i = 0, len = s.length; i < len; i++){
23629 indexes.push(s[i].nodeIndex);
23635 * Clear all selections
23636 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23638 clearSelections : function(suppressEvent){
23639 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23640 this.cmp.elements = this.selections;
23641 this.cmp.removeClass(this.selectedClass);
23642 this.selections = [];
23643 if(!suppressEvent){
23644 this.fireEvent("selectionchange", this, this.selections);
23650 * Returns true if the passed node is selected
23651 * @param {HTMLElement/Number} node The node or node index
23652 * @return {Boolean}
23654 isSelected : function(node){
23655 var s = this.selections;
23659 node = this.getNode(node);
23660 return s.indexOf(node) !== -1;
23665 * @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
23666 * @param {Boolean} keepExisting (optional) true to keep existing selections
23667 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23669 select : function(nodeInfo, keepExisting, suppressEvent){
23670 if(nodeInfo instanceof Array){
23672 this.clearSelections(true);
23674 for(var i = 0, len = nodeInfo.length; i < len; i++){
23675 this.select(nodeInfo[i], true, true);
23678 var node = this.getNode(nodeInfo);
23679 if(node && !this.isSelected(node)){
23681 this.clearSelections(true);
23683 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23684 Roo.fly(node).addClass(this.selectedClass);
23685 this.selections.push(node);
23686 if(!suppressEvent){
23687 this.fireEvent("selectionchange", this, this.selections);
23695 * Gets a template node.
23696 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23697 * @return {HTMLElement} The node or null if it wasn't found
23699 getNode : function(nodeInfo){
23700 if(typeof nodeInfo == "string"){
23701 return document.getElementById(nodeInfo);
23702 }else if(typeof nodeInfo == "number"){
23703 return this.nodes[nodeInfo];
23709 * Gets a range template nodes.
23710 * @param {Number} startIndex
23711 * @param {Number} endIndex
23712 * @return {Array} An array of nodes
23714 getNodes : function(start, end){
23715 var ns = this.nodes;
23716 start = start || 0;
23717 end = typeof end == "undefined" ? ns.length - 1 : end;
23720 for(var i = start; i <= end; i++){
23724 for(var i = start; i >= end; i--){
23732 * Finds the index of the passed node
23733 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23734 * @return {Number} The index of the node or -1
23736 indexOf : function(node){
23737 node = this.getNode(node);
23738 if(typeof node.nodeIndex == "number"){
23739 return node.nodeIndex;
23741 var ns = this.nodes;
23742 for(var i = 0, len = ns.length; i < len; i++){
23752 * Ext JS Library 1.1.1
23753 * Copyright(c) 2006-2007, Ext JS, LLC.
23755 * Originally Released Under LGPL - original licence link has changed is not relivant.
23758 * <script type="text/javascript">
23762 * @class Roo.JsonView
23763 * @extends Roo.View
23764 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23766 var view = new Roo.JsonView({
23767 container: "my-element",
23768 template: '<div id="{id}">{foo} - {bar}</div>', // auto create template
23773 // listen for node click?
23774 view.on("click", function(vw, index, node, e){
23775 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23778 // direct load of JSON data
23779 view.load("foobar.php");
23781 // Example from my blog list
23782 var tpl = new Roo.Template(
23783 '<div class="entry">' +
23784 '<a class="entry-title" href="{link}">{title}</a>' +
23785 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23786 "</div><hr />"
23789 var moreView = new Roo.JsonView({
23790 container : "entry-list",
23794 moreView.on("beforerender", this.sortEntries, this);
23796 url: "/blog/get-posts.php",
23797 params: "allposts=true",
23798 text: "Loading Blog Entries..."
23802 * Note: old code is supported with arguments : (container, template, config)
23806 * Create a new JsonView
23808 * @param {Object} config The config object
23811 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
23814 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
23816 var um = this.el.getUpdateManager();
23817 um.setRenderer(this);
23818 um.on("update", this.onLoad, this);
23819 um.on("failure", this.onLoadException, this);
23822 * @event beforerender
23823 * Fires before rendering of the downloaded JSON data.
23824 * @param {Roo.JsonView} this
23825 * @param {Object} data The JSON data loaded
23829 * Fires when data is loaded.
23830 * @param {Roo.JsonView} this
23831 * @param {Object} data The JSON data loaded
23832 * @param {Object} response The raw Connect response object
23835 * @event loadexception
23836 * Fires when loading fails.
23837 * @param {Roo.JsonView} this
23838 * @param {Object} response The raw Connect response object
23841 'beforerender' : true,
23843 'loadexception' : true
23846 Roo.extend(Roo.JsonView, Roo.View, {
23848 * @type {String} The root property in the loaded JSON object that contains the data
23853 * Refreshes the view.
23855 refresh : function(){
23856 this.clearSelections();
23857 this.el.update("");
23859 var o = this.jsonData;
23860 if(o && o.length > 0){
23861 for(var i = 0, len = o.length; i < len; i++){
23862 var data = this.prepareData(o[i], i, o);
23863 html[html.length] = this.tpl.apply(data);
23866 html.push(this.emptyText);
23868 this.el.update(html.join(""));
23869 this.nodes = this.el.dom.childNodes;
23870 this.updateIndexes(0);
23874 * 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.
23875 * @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:
23878 url: "your-url.php",
23879 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
23880 callback: yourFunction,
23881 scope: yourObject, //(optional scope)
23884 text: "Loading...",
23889 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
23890 * 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.
23891 * @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}
23892 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
23893 * @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.
23896 var um = this.el.getUpdateManager();
23897 um.update.apply(um, arguments);
23900 render : function(el, response){
23901 this.clearSelections();
23902 this.el.update("");
23905 o = Roo.util.JSON.decode(response.responseText);
23908 o = /** eval:var:o */ eval("o." + this.jsonRoot);
23913 * The current JSON data or null
23916 this.beforeRender();
23921 * Get the number of records in the current JSON dataset
23924 getCount : function(){
23925 return this.jsonData ? this.jsonData.length : 0;
23929 * Returns the JSON object for the specified node(s)
23930 * @param {HTMLElement/Array} node The node or an array of nodes
23931 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
23932 * you get the JSON object for the node
23934 getNodeData : function(node){
23935 if(node instanceof Array){
23937 for(var i = 0, len = node.length; i < len; i++){
23938 data.push(this.getNodeData(node[i]));
23942 return this.jsonData[this.indexOf(node)] || null;
23945 beforeRender : function(){
23946 this.snapshot = this.jsonData;
23948 this.sort.apply(this, this.sortInfo);
23950 this.fireEvent("beforerender", this, this.jsonData);
23953 onLoad : function(el, o){
23954 this.fireEvent("load", this, this.jsonData, o);
23957 onLoadException : function(el, o){
23958 this.fireEvent("loadexception", this, o);
23962 * Filter the data by a specific property.
23963 * @param {String} property A property on your JSON objects
23964 * @param {String/RegExp} value Either string that the property values
23965 * should start with, or a RegExp to test against the property
23967 filter : function(property, value){
23970 var ss = this.snapshot;
23971 if(typeof value == "string"){
23972 var vlen = value.length;
23974 this.clearFilter();
23977 value = value.toLowerCase();
23978 for(var i = 0, len = ss.length; i < len; i++){
23980 if(o[property].substr(0, vlen).toLowerCase() == value){
23984 } else if(value.exec){ // regex?
23985 for(var i = 0, len = ss.length; i < len; i++){
23987 if(value.test(o[property])){
23994 this.jsonData = data;
24000 * Filter by a function. The passed function will be called with each
24001 * object in the current dataset. If the function returns true the value is kept,
24002 * otherwise it is filtered.
24003 * @param {Function} fn
24004 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24006 filterBy : function(fn, scope){
24009 var ss = this.snapshot;
24010 for(var i = 0, len = ss.length; i < len; i++){
24012 if(fn.call(scope || this, o)){
24016 this.jsonData = data;
24022 * Clears the current filter.
24024 clearFilter : function(){
24025 if(this.snapshot && this.jsonData != this.snapshot){
24026 this.jsonData = this.snapshot;
24033 * Sorts the data for this view and refreshes it.
24034 * @param {String} property A property on your JSON objects to sort on
24035 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24036 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24038 sort : function(property, dir, sortType){
24039 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24042 var dsc = dir && dir.toLowerCase() == "desc";
24043 var f = function(o1, o2){
24044 var v1 = sortType ? sortType(o1[p]) : o1[p];
24045 var v2 = sortType ? sortType(o2[p]) : o2[p];
24048 return dsc ? +1 : -1;
24049 } else if(v1 > v2){
24050 return dsc ? -1 : +1;
24055 this.jsonData.sort(f);
24057 if(this.jsonData != this.snapshot){
24058 this.snapshot.sort(f);
24064 * Ext JS Library 1.1.1
24065 * Copyright(c) 2006-2007, Ext JS, LLC.
24067 * Originally Released Under LGPL - original licence link has changed is not relivant.
24070 * <script type="text/javascript">
24075 * @class Roo.ColorPalette
24076 * @extends Roo.Component
24077 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24078 * Here's an example of typical usage:
24080 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24081 cp.render('my-div');
24083 cp.on('select', function(palette, selColor){
24084 // do something with selColor
24088 * Create a new ColorPalette
24089 * @param {Object} config The config object
24091 Roo.ColorPalette = function(config){
24092 Roo.ColorPalette.superclass.constructor.call(this, config);
24096 * Fires when a color is selected
24097 * @param {ColorPalette} this
24098 * @param {String} color The 6-digit color hex code (without the # symbol)
24104 this.on("select", this.handler, this.scope, true);
24107 Roo.extend(Roo.ColorPalette, Roo.Component, {
24109 * @cfg {String} itemCls
24110 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24112 itemCls : "x-color-palette",
24114 * @cfg {String} value
24115 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24116 * the hex codes are case-sensitive.
24119 clickEvent:'click',
24121 ctype: "Roo.ColorPalette",
24124 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24126 allowReselect : false,
24129 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24130 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24131 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24132 * of colors with the width setting until the box is symmetrical.</p>
24133 * <p>You can override individual colors if needed:</p>
24135 var cp = new Roo.ColorPalette();
24136 cp.colors[0] = "FF0000"; // change the first box to red
24139 Or you can provide a custom array of your own for complete control:
24141 var cp = new Roo.ColorPalette();
24142 cp.colors = ["000000", "993300", "333300"];
24147 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24148 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24149 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24150 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24151 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24155 onRender : function(container, position){
24156 var t = new Roo.MasterTemplate(
24157 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24159 var c = this.colors;
24160 for(var i = 0, len = c.length; i < len; i++){
24163 var el = document.createElement("div");
24164 el.className = this.itemCls;
24166 container.dom.insertBefore(el, position);
24167 this.el = Roo.get(el);
24168 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24169 if(this.clickEvent != 'click'){
24170 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24175 afterRender : function(){
24176 Roo.ColorPalette.superclass.afterRender.call(this);
24178 var s = this.value;
24185 handleClick : function(e, t){
24186 e.preventDefault();
24187 if(!this.disabled){
24188 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24189 this.select(c.toUpperCase());
24194 * Selects the specified color in the palette (fires the select event)
24195 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24197 select : function(color){
24198 color = color.replace("#", "");
24199 if(color != this.value || this.allowReselect){
24202 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24204 el.child("a.color-"+color).addClass("x-color-palette-sel");
24205 this.value = color;
24206 this.fireEvent("select", this, color);
24211 * Ext JS Library 1.1.1
24212 * Copyright(c) 2006-2007, Ext JS, LLC.
24214 * Originally Released Under LGPL - original licence link has changed is not relivant.
24217 * <script type="text/javascript">
24221 * @class Roo.DatePicker
24222 * @extends Roo.Component
24223 * Simple date picker class.
24225 * Create a new DatePicker
24226 * @param {Object} config The config object
24228 Roo.DatePicker = function(config){
24229 Roo.DatePicker.superclass.constructor.call(this, config);
24231 this.value = config && config.value ?
24232 config.value.clearTime() : new Date().clearTime();
24237 * Fires when a date is selected
24238 * @param {DatePicker} this
24239 * @param {Date} date The selected date
24245 this.on("select", this.handler, this.scope || this);
24247 // build the disabledDatesRE
24248 if(!this.disabledDatesRE && this.disabledDates){
24249 var dd = this.disabledDates;
24251 for(var i = 0; i < dd.length; i++){
24253 if(i != dd.length-1) re += "|";
24255 this.disabledDatesRE = new RegExp(re + ")");
24259 Roo.extend(Roo.DatePicker, Roo.Component, {
24261 * @cfg {String} todayText
24262 * The text to display on the button that selects the current date (defaults to "Today")
24264 todayText : "Today",
24266 * @cfg {String} okText
24267 * The text to display on the ok button
24269 okText : " OK ", //   to give the user extra clicking room
24271 * @cfg {String} cancelText
24272 * The text to display on the cancel button
24274 cancelText : "Cancel",
24276 * @cfg {String} todayTip
24277 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24279 todayTip : "{0} (Spacebar)",
24281 * @cfg {Date} minDate
24282 * Minimum allowable date (JavaScript date object, defaults to null)
24286 * @cfg {Date} maxDate
24287 * Maximum allowable date (JavaScript date object, defaults to null)
24291 * @cfg {String} minText
24292 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24294 minText : "This date is before the minimum date",
24296 * @cfg {String} maxText
24297 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24299 maxText : "This date is after the maximum date",
24301 * @cfg {String} format
24302 * The default date format string which can be overriden for localization support. The format must be
24303 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24307 * @cfg {Array} disabledDays
24308 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24310 disabledDays : null,
24312 * @cfg {String} disabledDaysText
24313 * The tooltip to display when the date falls on a disabled day (defaults to "")
24315 disabledDaysText : "",
24317 * @cfg {RegExp} disabledDatesRE
24318 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24320 disabledDatesRE : null,
24322 * @cfg {String} disabledDatesText
24323 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24325 disabledDatesText : "",
24327 * @cfg {Boolean} constrainToViewport
24328 * True to constrain the date picker to the viewport (defaults to true)
24330 constrainToViewport : true,
24332 * @cfg {Array} monthNames
24333 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24335 monthNames : Date.monthNames,
24337 * @cfg {Array} dayNames
24338 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24340 dayNames : Date.dayNames,
24342 * @cfg {String} nextText
24343 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24345 nextText: 'Next Month (Control+Right)',
24347 * @cfg {String} prevText
24348 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24350 prevText: 'Previous Month (Control+Left)',
24352 * @cfg {String} monthYearText
24353 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24355 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24357 * @cfg {Number} startDay
24358 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24362 * @cfg {Bool} showClear
24363 * Show a clear button (usefull for date form elements that can be blank.)
24369 * Sets the value of the date field
24370 * @param {Date} value The date to set
24372 setValue : function(value){
24373 var old = this.value;
24374 this.value = value.clearTime(true);
24376 this.update(this.value);
24381 * Gets the current selected value of the date field
24382 * @return {Date} The selected date
24384 getValue : function(){
24389 focus : function(){
24391 this.update(this.activeDate);
24396 onRender : function(container, position){
24398 '<table cellspacing="0">',
24399 '<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>',
24400 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24401 var dn = this.dayNames;
24402 for(var i = 0; i < 7; i++){
24403 var d = this.startDay+i;
24407 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24409 m[m.length] = "</tr></thead><tbody><tr>";
24410 for(var i = 0; i < 42; i++) {
24411 if(i % 7 == 0 && i != 0){
24412 m[m.length] = "</tr><tr>";
24414 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24416 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24417 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24419 var el = document.createElement("div");
24420 el.className = "x-date-picker";
24421 el.innerHTML = m.join("");
24423 container.dom.insertBefore(el, position);
24425 this.el = Roo.get(el);
24426 this.eventEl = Roo.get(el.firstChild);
24428 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24429 handler: this.showPrevMonth,
24431 preventDefault:true,
24435 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24436 handler: this.showNextMonth,
24438 preventDefault:true,
24442 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24444 this.monthPicker = this.el.down('div.x-date-mp');
24445 this.monthPicker.enableDisplayMode('block');
24447 var kn = new Roo.KeyNav(this.eventEl, {
24448 "left" : function(e){
24450 this.showPrevMonth() :
24451 this.update(this.activeDate.add("d", -1));
24454 "right" : function(e){
24456 this.showNextMonth() :
24457 this.update(this.activeDate.add("d", 1));
24460 "up" : function(e){
24462 this.showNextYear() :
24463 this.update(this.activeDate.add("d", -7));
24466 "down" : function(e){
24468 this.showPrevYear() :
24469 this.update(this.activeDate.add("d", 7));
24472 "pageUp" : function(e){
24473 this.showNextMonth();
24476 "pageDown" : function(e){
24477 this.showPrevMonth();
24480 "enter" : function(e){
24481 e.stopPropagation();
24488 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24490 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24492 this.el.unselectable();
24494 this.cells = this.el.select("table.x-date-inner tbody td");
24495 this.textNodes = this.el.query("table.x-date-inner tbody span");
24497 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24499 tooltip: this.monthYearText
24502 this.mbtn.on('click', this.showMonthPicker, this);
24503 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24506 var today = (new Date()).dateFormat(this.format);
24508 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24510 text: String.format(this.todayText, today),
24511 tooltip: String.format(this.todayTip, today),
24512 handler: this.selectToday,
24516 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24519 if (this.showClear) {
24521 baseTb.add( new Roo.Toolbar.Fill());
24524 cls: 'x-btn-icon x-btn-clear',
24525 handler: function() {
24527 this.fireEvent("select", this, '');
24537 this.update(this.value);
24540 createMonthPicker : function(){
24541 if(!this.monthPicker.dom.firstChild){
24542 var buf = ['<table border="0" cellspacing="0">'];
24543 for(var i = 0; i < 6; i++){
24545 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24546 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24548 '<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>' :
24549 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24553 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24555 '</button><button type="button" class="x-date-mp-cancel">',
24557 '</button></td></tr>',
24560 this.monthPicker.update(buf.join(''));
24561 this.monthPicker.on('click', this.onMonthClick, this);
24562 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24564 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24565 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24567 this.mpMonths.each(function(m, a, i){
24570 m.dom.xmonth = 5 + Math.round(i * .5);
24572 m.dom.xmonth = Math.round((i-1) * .5);
24578 showMonthPicker : function(){
24579 this.createMonthPicker();
24580 var size = this.el.getSize();
24581 this.monthPicker.setSize(size);
24582 this.monthPicker.child('table').setSize(size);
24584 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24585 this.updateMPMonth(this.mpSelMonth);
24586 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24587 this.updateMPYear(this.mpSelYear);
24589 this.monthPicker.slideIn('t', {duration:.2});
24592 updateMPYear : function(y){
24594 var ys = this.mpYears.elements;
24595 for(var i = 1; i <= 10; i++){
24596 var td = ys[i-1], y2;
24598 y2 = y + Math.round(i * .5);
24599 td.firstChild.innerHTML = y2;
24602 y2 = y - (5-Math.round(i * .5));
24603 td.firstChild.innerHTML = y2;
24606 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24610 updateMPMonth : function(sm){
24611 this.mpMonths.each(function(m, a, i){
24612 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24616 selectMPMonth: function(m){
24620 onMonthClick : function(e, t){
24622 var el = new Roo.Element(t), pn;
24623 if(el.is('button.x-date-mp-cancel')){
24624 this.hideMonthPicker();
24626 else if(el.is('button.x-date-mp-ok')){
24627 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24628 this.hideMonthPicker();
24630 else if(pn = el.up('td.x-date-mp-month', 2)){
24631 this.mpMonths.removeClass('x-date-mp-sel');
24632 pn.addClass('x-date-mp-sel');
24633 this.mpSelMonth = pn.dom.xmonth;
24635 else if(pn = el.up('td.x-date-mp-year', 2)){
24636 this.mpYears.removeClass('x-date-mp-sel');
24637 pn.addClass('x-date-mp-sel');
24638 this.mpSelYear = pn.dom.xyear;
24640 else if(el.is('a.x-date-mp-prev')){
24641 this.updateMPYear(this.mpyear-10);
24643 else if(el.is('a.x-date-mp-next')){
24644 this.updateMPYear(this.mpyear+10);
24648 onMonthDblClick : function(e, t){
24650 var el = new Roo.Element(t), pn;
24651 if(pn = el.up('td.x-date-mp-month', 2)){
24652 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24653 this.hideMonthPicker();
24655 else if(pn = el.up('td.x-date-mp-year', 2)){
24656 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24657 this.hideMonthPicker();
24661 hideMonthPicker : function(disableAnim){
24662 if(this.monthPicker){
24663 if(disableAnim === true){
24664 this.monthPicker.hide();
24666 this.monthPicker.slideOut('t', {duration:.2});
24672 showPrevMonth : function(e){
24673 this.update(this.activeDate.add("mo", -1));
24677 showNextMonth : function(e){
24678 this.update(this.activeDate.add("mo", 1));
24682 showPrevYear : function(){
24683 this.update(this.activeDate.add("y", -1));
24687 showNextYear : function(){
24688 this.update(this.activeDate.add("y", 1));
24692 handleMouseWheel : function(e){
24693 var delta = e.getWheelDelta();
24695 this.showPrevMonth();
24697 } else if(delta < 0){
24698 this.showNextMonth();
24704 handleDateClick : function(e, t){
24706 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24707 this.setValue(new Date(t.dateValue));
24708 this.fireEvent("select", this, this.value);
24713 selectToday : function(){
24714 this.setValue(new Date().clearTime());
24715 this.fireEvent("select", this, this.value);
24719 update : function(date){
24720 var vd = this.activeDate;
24721 this.activeDate = date;
24723 var t = date.getTime();
24724 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24725 this.cells.removeClass("x-date-selected");
24726 this.cells.each(function(c){
24727 if(c.dom.firstChild.dateValue == t){
24728 c.addClass("x-date-selected");
24729 setTimeout(function(){
24730 try{c.dom.firstChild.focus();}catch(e){}
24738 var days = date.getDaysInMonth();
24739 var firstOfMonth = date.getFirstDateOfMonth();
24740 var startingPos = firstOfMonth.getDay()-this.startDay;
24742 if(startingPos <= this.startDay){
24746 var pm = date.add("mo", -1);
24747 var prevStart = pm.getDaysInMonth()-startingPos;
24749 var cells = this.cells.elements;
24750 var textEls = this.textNodes;
24751 days += startingPos;
24753 // convert everything to numbers so it's fast
24754 var day = 86400000;
24755 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24756 var today = new Date().clearTime().getTime();
24757 var sel = date.clearTime().getTime();
24758 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24759 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24760 var ddMatch = this.disabledDatesRE;
24761 var ddText = this.disabledDatesText;
24762 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24763 var ddaysText = this.disabledDaysText;
24764 var format = this.format;
24766 var setCellClass = function(cal, cell){
24768 var t = d.getTime();
24769 cell.firstChild.dateValue = t;
24771 cell.className += " x-date-today";
24772 cell.title = cal.todayText;
24775 cell.className += " x-date-selected";
24776 setTimeout(function(){
24777 try{cell.firstChild.focus();}catch(e){}
24782 cell.className = " x-date-disabled";
24783 cell.title = cal.minText;
24787 cell.className = " x-date-disabled";
24788 cell.title = cal.maxText;
24792 if(ddays.indexOf(d.getDay()) != -1){
24793 cell.title = ddaysText;
24794 cell.className = " x-date-disabled";
24797 if(ddMatch && format){
24798 var fvalue = d.dateFormat(format);
24799 if(ddMatch.test(fvalue)){
24800 cell.title = ddText.replace("%0", fvalue);
24801 cell.className = " x-date-disabled";
24807 for(; i < startingPos; i++) {
24808 textEls[i].innerHTML = (++prevStart);
24809 d.setDate(d.getDate()+1);
24810 cells[i].className = "x-date-prevday";
24811 setCellClass(this, cells[i]);
24813 for(; i < days; i++){
24814 intDay = i - startingPos + 1;
24815 textEls[i].innerHTML = (intDay);
24816 d.setDate(d.getDate()+1);
24817 cells[i].className = "x-date-active";
24818 setCellClass(this, cells[i]);
24821 for(; i < 42; i++) {
24822 textEls[i].innerHTML = (++extraDays);
24823 d.setDate(d.getDate()+1);
24824 cells[i].className = "x-date-nextday";
24825 setCellClass(this, cells[i]);
24828 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
24830 if(!this.internalRender){
24831 var main = this.el.dom.firstChild;
24832 var w = main.offsetWidth;
24833 this.el.setWidth(w + this.el.getBorderWidth("lr"));
24834 Roo.fly(main).setWidth(w);
24835 this.internalRender = true;
24836 // opera does not respect the auto grow header center column
24837 // then, after it gets a width opera refuses to recalculate
24838 // without a second pass
24839 if(Roo.isOpera && !this.secondPass){
24840 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
24841 this.secondPass = true;
24842 this.update.defer(10, this, [date]);
24848 * Ext JS Library 1.1.1
24849 * Copyright(c) 2006-2007, Ext JS, LLC.
24851 * Originally Released Under LGPL - original licence link has changed is not relivant.
24854 * <script type="text/javascript">
24857 * @class Roo.TabPanel
24858 * @extends Roo.util.Observable
24859 * A lightweight tab container.
24863 // basic tabs 1, built from existing content
24864 var tabs = new Roo.TabPanel("tabs1");
24865 tabs.addTab("script", "View Script");
24866 tabs.addTab("markup", "View Markup");
24867 tabs.activate("script");
24869 // more advanced tabs, built from javascript
24870 var jtabs = new Roo.TabPanel("jtabs");
24871 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
24873 // set up the UpdateManager
24874 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
24875 var updater = tab2.getUpdateManager();
24876 updater.setDefaultUrl("ajax1.htm");
24877 tab2.on('activate', updater.refresh, updater, true);
24879 // Use setUrl for Ajax loading
24880 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
24881 tab3.setUrl("ajax2.htm", null, true);
24884 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
24887 jtabs.activate("jtabs-1");
24890 * Create a new TabPanel.
24891 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
24892 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
24894 Roo.TabPanel = function(container, config){
24896 * The container element for this TabPanel.
24897 * @type Roo.Element
24899 this.el = Roo.get(container, true);
24901 if(typeof config == "boolean"){
24902 this.tabPosition = config ? "bottom" : "top";
24904 Roo.apply(this, config);
24907 if(this.tabPosition == "bottom"){
24908 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24909 this.el.addClass("x-tabs-bottom");
24911 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
24912 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
24913 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
24915 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
24917 if(this.tabPosition != "bottom"){
24918 /** The body element that contains {@link Roo.TabPanelItem} bodies.
24919 * @type Roo.Element
24921 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24922 this.el.addClass("x-tabs-top");
24926 this.bodyEl.setStyle("position", "relative");
24928 this.active = null;
24929 this.activateDelegate = this.activate.createDelegate(this);
24934 * Fires when the active tab changes
24935 * @param {Roo.TabPanel} this
24936 * @param {Roo.TabPanelItem} activePanel The new active tab
24940 * @event beforetabchange
24941 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
24942 * @param {Roo.TabPanel} this
24943 * @param {Object} e Set cancel to true on this object to cancel the tab change
24944 * @param {Roo.TabPanelItem} tab The tab being changed to
24946 "beforetabchange" : true
24949 Roo.EventManager.onWindowResize(this.onResize, this);
24950 this.cpad = this.el.getPadding("lr");
24951 this.hiddenCount = 0;
24953 Roo.TabPanel.superclass.constructor.call(this);
24956 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
24958 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
24960 tabPosition : "top",
24962 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
24964 currentTabWidth : 0,
24966 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
24970 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
24974 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
24976 preferredTabWidth : 175,
24978 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
24980 resizeTabs : false,
24982 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
24984 monitorResize : true,
24987 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
24988 * @param {String} id The id of the div to use <b>or create</b>
24989 * @param {String} text The text for the tab
24990 * @param {String} content (optional) Content to put in the TabPanelItem body
24991 * @param {Boolean} closable (optional) True to create a close icon on the tab
24992 * @return {Roo.TabPanelItem} The created TabPanelItem
24994 addTab : function(id, text, content, closable){
24995 var item = new Roo.TabPanelItem(this, id, text, closable);
24996 this.addTabItem(item);
24998 item.setContent(content);
25004 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25005 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25006 * @return {Roo.TabPanelItem}
25008 getTab : function(id){
25009 return this.items[id];
25013 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25014 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25016 hideTab : function(id){
25017 var t = this.items[id];
25020 this.hiddenCount++;
25021 this.autoSizeTabs();
25026 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25027 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25029 unhideTab : function(id){
25030 var t = this.items[id];
25032 t.setHidden(false);
25033 this.hiddenCount--;
25034 this.autoSizeTabs();
25039 * Adds an existing {@link Roo.TabPanelItem}.
25040 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25042 addTabItem : function(item){
25043 this.items[item.id] = item;
25044 this.items.push(item);
25045 if(this.resizeTabs){
25046 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25047 this.autoSizeTabs();
25054 * Removes a {@link Roo.TabPanelItem}.
25055 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25057 removeTab : function(id){
25058 var items = this.items;
25059 var tab = items[id];
25061 var index = items.indexOf(tab);
25062 if(this.active == tab && items.length > 1){
25063 var newTab = this.getNextAvailable(index);
25064 if(newTab)newTab.activate();
25066 this.stripEl.dom.removeChild(tab.pnode.dom);
25067 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25068 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25070 items.splice(index, 1);
25071 delete this.items[tab.id];
25072 tab.fireEvent("close", tab);
25073 tab.purgeListeners();
25074 this.autoSizeTabs();
25077 getNextAvailable : function(start){
25078 var items = this.items;
25080 // look for a next tab that will slide over to
25081 // replace the one being removed
25082 while(index < items.length){
25083 var item = items[++index];
25084 if(item && !item.isHidden()){
25088 // if one isn't found select the previous tab (on the left)
25091 var item = items[--index];
25092 if(item && !item.isHidden()){
25100 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25101 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25103 disableTab : function(id){
25104 var tab = this.items[id];
25105 if(tab && this.active != tab){
25111 * Enables a {@link Roo.TabPanelItem} that is disabled.
25112 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25114 enableTab : function(id){
25115 var tab = this.items[id];
25120 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25121 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25122 * @return {Roo.TabPanelItem} The TabPanelItem.
25124 activate : function(id){
25125 var tab = this.items[id];
25129 if(tab == this.active || tab.disabled){
25133 this.fireEvent("beforetabchange", this, e, tab);
25134 if(e.cancel !== true && !tab.disabled){
25136 this.active.hide();
25138 this.active = this.items[id];
25139 this.active.show();
25140 this.fireEvent("tabchange", this, this.active);
25146 * Gets the active {@link Roo.TabPanelItem}.
25147 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25149 getActiveTab : function(){
25150 return this.active;
25154 * Updates the tab body element to fit the height of the container element
25155 * for overflow scrolling
25156 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25158 syncHeight : function(targetHeight){
25159 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25160 var bm = this.bodyEl.getMargins();
25161 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25162 this.bodyEl.setHeight(newHeight);
25166 onResize : function(){
25167 if(this.monitorResize){
25168 this.autoSizeTabs();
25173 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25175 beginUpdate : function(){
25176 this.updating = true;
25180 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25182 endUpdate : function(){
25183 this.updating = false;
25184 this.autoSizeTabs();
25188 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25190 autoSizeTabs : function(){
25191 var count = this.items.length;
25192 var vcount = count - this.hiddenCount;
25193 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25194 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25195 var availWidth = Math.floor(w / vcount);
25196 var b = this.stripBody;
25197 if(b.getWidth() > w){
25198 var tabs = this.items;
25199 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25200 if(availWidth < this.minTabWidth){
25201 /*if(!this.sleft){ // incomplete scrolling code
25202 this.createScrollButtons();
25205 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25208 if(this.currentTabWidth < this.preferredTabWidth){
25209 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25215 * Returns the number of tabs in this TabPanel.
25218 getCount : function(){
25219 return this.items.length;
25223 * Resizes all the tabs to the passed width
25224 * @param {Number} The new width
25226 setTabWidth : function(width){
25227 this.currentTabWidth = width;
25228 for(var i = 0, len = this.items.length; i < len; i++) {
25229 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25234 * Destroys this TabPanel
25235 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25237 destroy : function(removeEl){
25238 Roo.EventManager.removeResizeListener(this.onResize, this);
25239 for(var i = 0, len = this.items.length; i < len; i++){
25240 this.items[i].purgeListeners();
25242 if(removeEl === true){
25243 this.el.update("");
25250 * @class Roo.TabPanelItem
25251 * @extends Roo.util.Observable
25252 * Represents an individual item (tab plus body) in a TabPanel.
25253 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25254 * @param {String} id The id of this TabPanelItem
25255 * @param {String} text The text for the tab of this TabPanelItem
25256 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25258 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25260 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25261 * @type Roo.TabPanel
25263 this.tabPanel = tabPanel;
25265 * The id for this TabPanelItem
25270 this.disabled = false;
25274 this.loaded = false;
25275 this.closable = closable;
25278 * The body element for this TabPanelItem.
25279 * @type Roo.Element
25281 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25282 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25283 this.bodyEl.setStyle("display", "block");
25284 this.bodyEl.setStyle("zoom", "1");
25287 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25289 this.el = Roo.get(els.el, true);
25290 this.inner = Roo.get(els.inner, true);
25291 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25292 this.pnode = Roo.get(els.el.parentNode, true);
25293 this.el.on("mousedown", this.onTabMouseDown, this);
25294 this.el.on("click", this.onTabClick, this);
25297 var c = Roo.get(els.close, true);
25298 c.dom.title = this.closeText;
25299 c.addClassOnOver("close-over");
25300 c.on("click", this.closeClick, this);
25306 * Fires when this tab becomes the active tab.
25307 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25308 * @param {Roo.TabPanelItem} this
25312 * @event beforeclose
25313 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25314 * @param {Roo.TabPanelItem} this
25315 * @param {Object} e Set cancel to true on this object to cancel the close.
25317 "beforeclose": true,
25320 * Fires when this tab is closed.
25321 * @param {Roo.TabPanelItem} this
25325 * @event deactivate
25326 * Fires when this tab is no longer the active tab.
25327 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25328 * @param {Roo.TabPanelItem} this
25330 "deactivate" : true
25332 this.hidden = false;
25334 Roo.TabPanelItem.superclass.constructor.call(this);
25337 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25338 purgeListeners : function(){
25339 Roo.util.Observable.prototype.purgeListeners.call(this);
25340 this.el.removeAllListeners();
25343 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25346 this.pnode.addClass("on");
25349 this.tabPanel.stripWrap.repaint();
25351 this.fireEvent("activate", this.tabPanel, this);
25355 * Returns true if this tab is the active tab.
25356 * @return {Boolean}
25358 isActive : function(){
25359 return this.tabPanel.getActiveTab() == this;
25363 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25366 this.pnode.removeClass("on");
25368 this.fireEvent("deactivate", this.tabPanel, this);
25371 hideAction : function(){
25372 this.bodyEl.hide();
25373 this.bodyEl.setStyle("position", "absolute");
25374 this.bodyEl.setLeft("-20000px");
25375 this.bodyEl.setTop("-20000px");
25378 showAction : function(){
25379 this.bodyEl.setStyle("position", "relative");
25380 this.bodyEl.setTop("");
25381 this.bodyEl.setLeft("");
25382 this.bodyEl.show();
25386 * Set the tooltip for the tab.
25387 * @param {String} tooltip The tab's tooltip
25389 setTooltip : function(text){
25390 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25391 this.textEl.dom.qtip = text;
25392 this.textEl.dom.removeAttribute('title');
25394 this.textEl.dom.title = text;
25398 onTabClick : function(e){
25399 e.preventDefault();
25400 this.tabPanel.activate(this.id);
25403 onTabMouseDown : function(e){
25404 e.preventDefault();
25405 this.tabPanel.activate(this.id);
25408 getWidth : function(){
25409 return this.inner.getWidth();
25412 setWidth : function(width){
25413 var iwidth = width - this.pnode.getPadding("lr");
25414 this.inner.setWidth(iwidth);
25415 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25416 this.pnode.setWidth(width);
25420 * Show or hide the tab
25421 * @param {Boolean} hidden True to hide or false to show.
25423 setHidden : function(hidden){
25424 this.hidden = hidden;
25425 this.pnode.setStyle("display", hidden ? "none" : "");
25429 * Returns true if this tab is "hidden"
25430 * @return {Boolean}
25432 isHidden : function(){
25433 return this.hidden;
25437 * Returns the text for this tab
25440 getText : function(){
25444 autoSize : function(){
25445 //this.el.beginMeasure();
25446 this.textEl.setWidth(1);
25447 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25448 //this.el.endMeasure();
25452 * Sets the text for the tab (Note: this also sets the tooltip text)
25453 * @param {String} text The tab's text and tooltip
25455 setText : function(text){
25457 this.textEl.update(text);
25458 this.setTooltip(text);
25459 if(!this.tabPanel.resizeTabs){
25464 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25466 activate : function(){
25467 this.tabPanel.activate(this.id);
25471 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25473 disable : function(){
25474 if(this.tabPanel.active != this){
25475 this.disabled = true;
25476 this.pnode.addClass("disabled");
25481 * Enables this TabPanelItem if it was previously disabled.
25483 enable : function(){
25484 this.disabled = false;
25485 this.pnode.removeClass("disabled");
25489 * Sets the content for this TabPanelItem.
25490 * @param {String} content The content
25491 * @param {Boolean} loadScripts true to look for and load scripts
25493 setContent : function(content, loadScripts){
25494 this.bodyEl.update(content, loadScripts);
25498 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25499 * @return {Roo.UpdateManager} The UpdateManager
25501 getUpdateManager : function(){
25502 return this.bodyEl.getUpdateManager();
25506 * Set a URL to be used to load the content for this TabPanelItem.
25507 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25508 * @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)
25509 * @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)
25510 * @return {Roo.UpdateManager} The UpdateManager
25512 setUrl : function(url, params, loadOnce){
25513 if(this.refreshDelegate){
25514 this.un('activate', this.refreshDelegate);
25516 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25517 this.on("activate", this.refreshDelegate);
25518 return this.bodyEl.getUpdateManager();
25522 _handleRefresh : function(url, params, loadOnce){
25523 if(!loadOnce || !this.loaded){
25524 var updater = this.bodyEl.getUpdateManager();
25525 updater.update(url, params, this._setLoaded.createDelegate(this));
25530 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25531 * Will fail silently if the setUrl method has not been called.
25532 * This does not activate the panel, just updates its content.
25534 refresh : function(){
25535 if(this.refreshDelegate){
25536 this.loaded = false;
25537 this.refreshDelegate();
25542 _setLoaded : function(){
25543 this.loaded = true;
25547 closeClick : function(e){
25550 this.fireEvent("beforeclose", this, o);
25551 if(o.cancel !== true){
25552 this.tabPanel.removeTab(this.id);
25556 * The text displayed in the tooltip for the close icon.
25559 closeText : "Close this tab"
25563 Roo.TabPanel.prototype.createStrip = function(container){
25564 var strip = document.createElement("div");
25565 strip.className = "x-tabs-wrap";
25566 container.appendChild(strip);
25570 Roo.TabPanel.prototype.createStripList = function(strip){
25571 // div wrapper for retard IE
25572 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>';
25573 return strip.firstChild.firstChild.firstChild.firstChild;
25576 Roo.TabPanel.prototype.createBody = function(container){
25577 var body = document.createElement("div");
25578 Roo.id(body, "tab-body");
25579 Roo.fly(body).addClass("x-tabs-body");
25580 container.appendChild(body);
25584 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25585 var body = Roo.getDom(id);
25587 body = document.createElement("div");
25590 Roo.fly(body).addClass("x-tabs-item-body");
25591 bodyEl.insertBefore(body, bodyEl.firstChild);
25595 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25596 var td = document.createElement("td");
25597 stripEl.appendChild(td);
25599 td.className = "x-tabs-closable";
25600 if(!this.closeTpl){
25601 this.closeTpl = new Roo.Template(
25602 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25603 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25604 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25607 var el = this.closeTpl.overwrite(td, {"text": text});
25608 var close = el.getElementsByTagName("div")[0];
25609 var inner = el.getElementsByTagName("em")[0];
25610 return {"el": el, "close": close, "inner": inner};
25613 this.tabTpl = new Roo.Template(
25614 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25615 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25618 var el = this.tabTpl.overwrite(td, {"text": text});
25619 var inner = el.getElementsByTagName("em")[0];
25620 return {"el": el, "inner": inner};
25624 * Ext JS Library 1.1.1
25625 * Copyright(c) 2006-2007, Ext JS, LLC.
25627 * Originally Released Under LGPL - original licence link has changed is not relivant.
25630 * <script type="text/javascript">
25634 * @class Roo.Button
25635 * @extends Roo.util.Observable
25636 * Simple Button class
25637 * @cfg {String} text The button text
25638 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25639 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25640 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25641 * @cfg {Object} scope The scope of the handler
25642 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25643 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25644 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25645 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25646 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25647 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25648 applies if enableToggle = true)
25649 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25650 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25651 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25653 * Create a new button
25654 * @param {Object} config The config object
25656 Roo.Button = function(renderTo, config)
25660 renderTo = config.renderTo || false;
25663 Roo.apply(this, config);
25667 * Fires when this button is clicked
25668 * @param {Button} this
25669 * @param {EventObject} e The click event
25674 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25675 * @param {Button} this
25676 * @param {Boolean} pressed
25681 * Fires when the mouse hovers over the button
25682 * @param {Button} this
25683 * @param {Event} e The event object
25685 'mouseover' : true,
25688 * Fires when the mouse exits the button
25689 * @param {Button} this
25690 * @param {Event} e The event object
25695 * Fires when the button is rendered
25696 * @param {Button} this
25701 this.menu = Roo.menu.MenuMgr.get(this.menu);
25704 this.render(renderTo);
25707 Roo.util.Observable.call(this);
25710 Roo.extend(Roo.Button, Roo.util.Observable, {
25716 * Read-only. True if this button is hidden
25721 * Read-only. True if this button is disabled
25726 * Read-only. True if this button is pressed (only if enableToggle = true)
25732 * @cfg {Number} tabIndex
25733 * The DOM tabIndex for this button (defaults to undefined)
25735 tabIndex : undefined,
25738 * @cfg {Boolean} enableToggle
25739 * True to enable pressed/not pressed toggling (defaults to false)
25741 enableToggle: false,
25743 * @cfg {Mixed} menu
25744 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25748 * @cfg {String} menuAlign
25749 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25751 menuAlign : "tl-bl?",
25754 * @cfg {String} iconCls
25755 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25757 iconCls : undefined,
25759 * @cfg {String} type
25760 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25765 menuClassTarget: 'tr',
25768 * @cfg {String} clickEvent
25769 * The type of event to map to the button's event handler (defaults to 'click')
25771 clickEvent : 'click',
25774 * @cfg {Boolean} handleMouseEvents
25775 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25777 handleMouseEvents : true,
25780 * @cfg {String} tooltipType
25781 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25783 tooltipType : 'qtip',
25786 * @cfg {String} cls
25787 * A CSS class to apply to the button's main element.
25791 * @cfg {Roo.Template} template (Optional)
25792 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25793 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25794 * require code modifications if required elements (e.g. a button) aren't present.
25798 render : function(renderTo){
25800 if(this.hideParent){
25801 this.parentEl = Roo.get(renderTo);
25803 if(!this.dhconfig){
25804 if(!this.template){
25805 if(!Roo.Button.buttonTemplate){
25806 // hideous table template
25807 Roo.Button.buttonTemplate = new Roo.Template(
25808 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
25809 '<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>',
25810 "</tr></tbody></table>");
25812 this.template = Roo.Button.buttonTemplate;
25814 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
25815 var btnEl = btn.child("button:first");
25816 btnEl.on('focus', this.onFocus, this);
25817 btnEl.on('blur', this.onBlur, this);
25819 btn.addClass(this.cls);
25822 btnEl.setStyle('background-image', 'url(' +this.icon +')');
25825 btnEl.addClass(this.iconCls);
25827 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
25830 if(this.tabIndex !== undefined){
25831 btnEl.dom.tabIndex = this.tabIndex;
25834 if(typeof this.tooltip == 'object'){
25835 Roo.QuickTips.tips(Roo.apply({
25839 btnEl.dom[this.tooltipType] = this.tooltip;
25843 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
25847 this.el.dom.id = this.el.id = this.id;
25850 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
25851 this.menu.on("show", this.onMenuShow, this);
25852 this.menu.on("hide", this.onMenuHide, this);
25854 btn.addClass("x-btn");
25855 if(Roo.isIE && !Roo.isIE7){
25856 this.autoWidth.defer(1, this);
25860 if(this.handleMouseEvents){
25861 btn.on("mouseover", this.onMouseOver, this);
25862 btn.on("mouseout", this.onMouseOut, this);
25863 btn.on("mousedown", this.onMouseDown, this);
25865 btn.on(this.clickEvent, this.onClick, this);
25866 //btn.on("mouseup", this.onMouseUp, this);
25873 Roo.ButtonToggleMgr.register(this);
25875 this.el.addClass("x-btn-pressed");
25878 var repeater = new Roo.util.ClickRepeater(btn,
25879 typeof this.repeat == "object" ? this.repeat : {}
25881 repeater.on("click", this.onClick, this);
25883 this.fireEvent('render', this);
25887 * Returns the button's underlying element
25888 * @return {Roo.Element} The element
25890 getEl : function(){
25895 * Destroys this Button and removes any listeners.
25897 destroy : function(){
25898 Roo.ButtonToggleMgr.unregister(this);
25899 this.el.removeAllListeners();
25900 this.purgeListeners();
25905 autoWidth : function(){
25907 this.el.setWidth("auto");
25908 if(Roo.isIE7 && Roo.isStrict){
25909 var ib = this.el.child('button');
25910 if(ib && ib.getWidth() > 20){
25912 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
25917 this.el.beginMeasure();
25919 if(this.el.getWidth() < this.minWidth){
25920 this.el.setWidth(this.minWidth);
25923 this.el.endMeasure();
25930 * Assigns this button's click handler
25931 * @param {Function} handler The function to call when the button is clicked
25932 * @param {Object} scope (optional) Scope for the function passed in
25934 setHandler : function(handler, scope){
25935 this.handler = handler;
25936 this.scope = scope;
25940 * Sets this button's text
25941 * @param {String} text The button text
25943 setText : function(text){
25946 this.el.child("td.x-btn-center button.x-btn-text").update(text);
25952 * Gets the text for this button
25953 * @return {String} The button text
25955 getText : function(){
25963 this.hidden = false;
25965 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
25973 this.hidden = true;
25975 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
25980 * Convenience function for boolean show/hide
25981 * @param {Boolean} visible True to show, false to hide
25983 setVisible: function(visible){
25992 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
25993 * @param {Boolean} state (optional) Force a particular state
25995 toggle : function(state){
25996 state = state === undefined ? !this.pressed : state;
25997 if(state != this.pressed){
25999 this.el.addClass("x-btn-pressed");
26000 this.pressed = true;
26001 this.fireEvent("toggle", this, true);
26003 this.el.removeClass("x-btn-pressed");
26004 this.pressed = false;
26005 this.fireEvent("toggle", this, false);
26007 if(this.toggleHandler){
26008 this.toggleHandler.call(this.scope || this, this, state);
26016 focus : function(){
26017 this.el.child('button:first').focus();
26021 * Disable this button
26023 disable : function(){
26025 this.el.addClass("x-btn-disabled");
26027 this.disabled = true;
26031 * Enable this button
26033 enable : function(){
26035 this.el.removeClass("x-btn-disabled");
26037 this.disabled = false;
26041 * Convenience function for boolean enable/disable
26042 * @param {Boolean} enabled True to enable, false to disable
26044 setDisabled : function(v){
26045 this[v !== true ? "enable" : "disable"]();
26049 onClick : function(e){
26051 e.preventDefault();
26056 if(!this.disabled){
26057 if(this.enableToggle){
26060 if(this.menu && !this.menu.isVisible()){
26061 this.menu.show(this.el, this.menuAlign);
26063 this.fireEvent("click", this, e);
26065 this.el.removeClass("x-btn-over");
26066 this.handler.call(this.scope || this, this, e);
26071 onMouseOver : function(e){
26072 if(!this.disabled){
26073 this.el.addClass("x-btn-over");
26074 this.fireEvent('mouseover', this, e);
26078 onMouseOut : function(e){
26079 if(!e.within(this.el, true)){
26080 this.el.removeClass("x-btn-over");
26081 this.fireEvent('mouseout', this, e);
26085 onFocus : function(e){
26086 if(!this.disabled){
26087 this.el.addClass("x-btn-focus");
26091 onBlur : function(e){
26092 this.el.removeClass("x-btn-focus");
26095 onMouseDown : function(e){
26096 if(!this.disabled && e.button == 0){
26097 this.el.addClass("x-btn-click");
26098 Roo.get(document).on('mouseup', this.onMouseUp, this);
26102 onMouseUp : function(e){
26104 this.el.removeClass("x-btn-click");
26105 Roo.get(document).un('mouseup', this.onMouseUp, this);
26109 onMenuShow : function(e){
26110 this.el.addClass("x-btn-menu-active");
26113 onMenuHide : function(e){
26114 this.el.removeClass("x-btn-menu-active");
26118 // Private utility class used by Button
26119 Roo.ButtonToggleMgr = function(){
26122 function toggleGroup(btn, state){
26124 var g = groups[btn.toggleGroup];
26125 for(var i = 0, l = g.length; i < l; i++){
26127 g[i].toggle(false);
26134 register : function(btn){
26135 if(!btn.toggleGroup){
26138 var g = groups[btn.toggleGroup];
26140 g = groups[btn.toggleGroup] = [];
26143 btn.on("toggle", toggleGroup);
26146 unregister : function(btn){
26147 if(!btn.toggleGroup){
26150 var g = groups[btn.toggleGroup];
26153 btn.un("toggle", toggleGroup);
26159 * Ext JS Library 1.1.1
26160 * Copyright(c) 2006-2007, Ext JS, LLC.
26162 * Originally Released Under LGPL - original licence link has changed is not relivant.
26165 * <script type="text/javascript">
26169 * @class Roo.SplitButton
26170 * @extends Roo.Button
26171 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26172 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26173 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26174 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26175 * @cfg {String} arrowTooltip The title attribute of the arrow
26177 * Create a new menu button
26178 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26179 * @param {Object} config The config object
26181 Roo.SplitButton = function(renderTo, config){
26182 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26184 * @event arrowclick
26185 * Fires when this button's arrow is clicked
26186 * @param {SplitButton} this
26187 * @param {EventObject} e The click event
26189 this.addEvents({"arrowclick":true});
26192 Roo.extend(Roo.SplitButton, Roo.Button, {
26193 render : function(renderTo){
26194 // this is one sweet looking template!
26195 var tpl = new Roo.Template(
26196 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26197 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26198 '<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>',
26199 "</tbody></table></td><td>",
26200 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26201 '<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>',
26202 "</tbody></table></td></tr></table>"
26204 var btn = tpl.append(renderTo, [this.text, this.type], true);
26205 var btnEl = btn.child("button");
26207 btn.addClass(this.cls);
26210 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26213 btnEl.addClass(this.iconCls);
26215 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26219 if(this.handleMouseEvents){
26220 btn.on("mouseover", this.onMouseOver, this);
26221 btn.on("mouseout", this.onMouseOut, this);
26222 btn.on("mousedown", this.onMouseDown, this);
26223 btn.on("mouseup", this.onMouseUp, this);
26225 btn.on(this.clickEvent, this.onClick, this);
26227 if(typeof this.tooltip == 'object'){
26228 Roo.QuickTips.tips(Roo.apply({
26232 btnEl.dom[this.tooltipType] = this.tooltip;
26235 if(this.arrowTooltip){
26236 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26245 this.el.addClass("x-btn-pressed");
26247 if(Roo.isIE && !Roo.isIE7){
26248 this.autoWidth.defer(1, this);
26253 this.menu.on("show", this.onMenuShow, this);
26254 this.menu.on("hide", this.onMenuHide, this);
26256 this.fireEvent('render', this);
26260 autoWidth : function(){
26262 var tbl = this.el.child("table:first");
26263 var tbl2 = this.el.child("table:last");
26264 this.el.setWidth("auto");
26265 tbl.setWidth("auto");
26266 if(Roo.isIE7 && Roo.isStrict){
26267 var ib = this.el.child('button:first');
26268 if(ib && ib.getWidth() > 20){
26270 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26275 this.el.beginMeasure();
26277 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26278 tbl.setWidth(this.minWidth-tbl2.getWidth());
26281 this.el.endMeasure();
26284 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26288 * Sets this button's click handler
26289 * @param {Function} handler The function to call when the button is clicked
26290 * @param {Object} scope (optional) Scope for the function passed above
26292 setHandler : function(handler, scope){
26293 this.handler = handler;
26294 this.scope = scope;
26298 * Sets this button's arrow click handler
26299 * @param {Function} handler The function to call when the arrow is clicked
26300 * @param {Object} scope (optional) Scope for the function passed above
26302 setArrowHandler : function(handler, scope){
26303 this.arrowHandler = handler;
26304 this.scope = scope;
26310 focus : function(){
26312 this.el.child("button:first").focus();
26317 onClick : function(e){
26318 e.preventDefault();
26319 if(!this.disabled){
26320 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26321 if(this.menu && !this.menu.isVisible()){
26322 this.menu.show(this.el, this.menuAlign);
26324 this.fireEvent("arrowclick", this, e);
26325 if(this.arrowHandler){
26326 this.arrowHandler.call(this.scope || this, this, e);
26329 this.fireEvent("click", this, e);
26331 this.handler.call(this.scope || this, this, e);
26337 onMouseDown : function(e){
26338 if(!this.disabled){
26339 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26343 onMouseUp : function(e){
26344 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26349 // backwards compat
26350 Roo.MenuButton = Roo.SplitButton;/*
26352 * Ext JS Library 1.1.1
26353 * Copyright(c) 2006-2007, Ext JS, LLC.
26355 * Originally Released Under LGPL - original licence link has changed is not relivant.
26358 * <script type="text/javascript">
26362 * @class Roo.Toolbar
26363 * Basic Toolbar class.
26365 * Creates a new Toolbar
26366 * @param {Object} config The config object
26368 Roo.Toolbar = function(container, buttons, config)
26370 /// old consturctor format still supported..
26371 if(container instanceof Array){ // omit the container for later rendering
26372 buttons = container;
26376 if (typeof(container) == 'object' && container.xtype) {
26377 config = container;
26378 container = config.container;
26379 buttons = config.buttons; // not really - use items!!
26382 if (config && config.items) {
26383 xitems = config.items;
26384 delete config.items;
26386 Roo.apply(this, config);
26387 this.buttons = buttons;
26390 this.render(container);
26392 Roo.each(xitems, function(b) {
26398 Roo.Toolbar.prototype = {
26400 * @cfg {Roo.data.Store} items
26401 * array of button configs or elements to add
26405 * @cfg {String/HTMLElement/Element} container
26406 * The id or element that will contain the toolbar
26409 render : function(ct){
26410 this.el = Roo.get(ct);
26412 this.el.addClass(this.cls);
26414 // using a table allows for vertical alignment
26415 // 100% width is needed by Safari...
26416 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26417 this.tr = this.el.child("tr", true);
26419 this.items = new Roo.util.MixedCollection(false, function(o){
26420 return o.id || ("item" + (++autoId));
26423 this.add.apply(this, this.buttons);
26424 delete this.buttons;
26429 * Adds element(s) to the toolbar -- this function takes a variable number of
26430 * arguments of mixed type and adds them to the toolbar.
26431 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26433 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26434 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26435 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26436 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26437 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26438 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26439 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26440 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26441 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26443 * @param {Mixed} arg2
26444 * @param {Mixed} etc.
26447 var a = arguments, l = a.length;
26448 for(var i = 0; i < l; i++){
26453 _add : function(el) {
26456 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26459 if (el.applyTo){ // some kind of form field
26460 return this.addField(el);
26462 if (el.render){ // some kind of Toolbar.Item
26463 return this.addItem(el);
26465 if (typeof el == "string"){ // string
26466 if(el == "separator" || el == "-"){
26467 return this.addSeparator();
26470 return this.addSpacer();
26473 return this.addFill();
26475 return this.addText(el);
26478 if(el.tagName){ // element
26479 return this.addElement(el);
26481 if(typeof el == "object"){ // must be button config?
26482 return this.addButton(el);
26484 // and now what?!?!
26490 * Add an Xtype element
26491 * @param {Object} xtype Xtype Object
26492 * @return {Object} created Object
26494 addxtype : function(e){
26495 return this.add(e);
26499 * Returns the Element for this toolbar.
26500 * @return {Roo.Element}
26502 getEl : function(){
26508 * @return {Roo.Toolbar.Item} The separator item
26510 addSeparator : function(){
26511 return this.addItem(new Roo.Toolbar.Separator());
26515 * Adds a spacer element
26516 * @return {Roo.Toolbar.Spacer} The spacer item
26518 addSpacer : function(){
26519 return this.addItem(new Roo.Toolbar.Spacer());
26523 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26524 * @return {Roo.Toolbar.Fill} The fill item
26526 addFill : function(){
26527 return this.addItem(new Roo.Toolbar.Fill());
26531 * Adds any standard HTML element to the toolbar
26532 * @param {String/HTMLElement/Element} el The element or id of the element to add
26533 * @return {Roo.Toolbar.Item} The element's item
26535 addElement : function(el){
26536 return this.addItem(new Roo.Toolbar.Item(el));
26539 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26540 * @type Roo.util.MixedCollection
26545 * Adds any Toolbar.Item or subclass
26546 * @param {Roo.Toolbar.Item} item
26547 * @return {Roo.Toolbar.Item} The item
26549 addItem : function(item){
26550 var td = this.nextBlock();
26552 this.items.add(item);
26557 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26558 * @param {Object/Array} config A button config or array of configs
26559 * @return {Roo.Toolbar.Button/Array}
26561 addButton : function(config){
26562 if(config instanceof Array){
26564 for(var i = 0, len = config.length; i < len; i++) {
26565 buttons.push(this.addButton(config[i]));
26570 if(!(config instanceof Roo.Toolbar.Button)){
26572 new Roo.Toolbar.SplitButton(config) :
26573 new Roo.Toolbar.Button(config);
26575 var td = this.nextBlock();
26582 * Adds text to the toolbar
26583 * @param {String} text The text to add
26584 * @return {Roo.Toolbar.Item} The element's item
26586 addText : function(text){
26587 return this.addItem(new Roo.Toolbar.TextItem(text));
26591 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26592 * @param {Number} index The index where the item is to be inserted
26593 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26594 * @return {Roo.Toolbar.Button/Item}
26596 insertButton : function(index, item){
26597 if(item instanceof Array){
26599 for(var i = 0, len = item.length; i < len; i++) {
26600 buttons.push(this.insertButton(index + i, item[i]));
26604 if (!(item instanceof Roo.Toolbar.Button)){
26605 item = new Roo.Toolbar.Button(item);
26607 var td = document.createElement("td");
26608 this.tr.insertBefore(td, this.tr.childNodes[index]);
26610 this.items.insert(index, item);
26615 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26616 * @param {Object} config
26617 * @return {Roo.Toolbar.Item} The element's item
26619 addDom : function(config, returnEl){
26620 var td = this.nextBlock();
26621 Roo.DomHelper.overwrite(td, config);
26622 var ti = new Roo.Toolbar.Item(td.firstChild);
26624 this.items.add(ti);
26629 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26630 * @type Roo.util.MixedCollection
26635 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26636 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26637 * @param {Roo.form.Field} field
26638 * @return {Roo.ToolbarItem}
26642 addField : function(field) {
26643 if (!this.fields) {
26645 this.fields = new Roo.util.MixedCollection(false, function(o){
26646 return o.id || ("item" + (++autoId));
26651 var td = this.nextBlock();
26653 var ti = new Roo.Toolbar.Item(td.firstChild);
26655 this.items.add(ti);
26656 this.fields.add(field);
26667 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26668 this.el.child('div').hide();
26676 this.el.child('div').show();
26680 nextBlock : function(){
26681 var td = document.createElement("td");
26682 this.tr.appendChild(td);
26687 destroy : function(){
26688 if(this.items){ // rendered?
26689 Roo.destroy.apply(Roo, this.items.items);
26691 if(this.fields){ // rendered?
26692 Roo.destroy.apply(Roo, this.fields.items);
26694 Roo.Element.uncache(this.el, this.tr);
26699 * @class Roo.Toolbar.Item
26700 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26702 * Creates a new Item
26703 * @param {HTMLElement} el
26705 Roo.Toolbar.Item = function(el){
26706 this.el = Roo.getDom(el);
26707 this.id = Roo.id(this.el);
26708 this.hidden = false;
26711 Roo.Toolbar.Item.prototype = {
26714 * Get this item's HTML Element
26715 * @return {HTMLElement}
26717 getEl : function(){
26722 render : function(td){
26724 td.appendChild(this.el);
26728 * Removes and destroys this item.
26730 destroy : function(){
26731 this.td.parentNode.removeChild(this.td);
26738 this.hidden = false;
26739 this.td.style.display = "";
26746 this.hidden = true;
26747 this.td.style.display = "none";
26751 * Convenience function for boolean show/hide.
26752 * @param {Boolean} visible true to show/false to hide
26754 setVisible: function(visible){
26763 * Try to focus this item.
26765 focus : function(){
26766 Roo.fly(this.el).focus();
26770 * Disables this item.
26772 disable : function(){
26773 Roo.fly(this.td).addClass("x-item-disabled");
26774 this.disabled = true;
26775 this.el.disabled = true;
26779 * Enables this item.
26781 enable : function(){
26782 Roo.fly(this.td).removeClass("x-item-disabled");
26783 this.disabled = false;
26784 this.el.disabled = false;
26790 * @class Roo.Toolbar.Separator
26791 * @extends Roo.Toolbar.Item
26792 * A simple toolbar separator class
26794 * Creates a new Separator
26796 Roo.Toolbar.Separator = function(){
26797 var s = document.createElement("span");
26798 s.className = "ytb-sep";
26799 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
26801 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
26802 enable:Roo.emptyFn,
26803 disable:Roo.emptyFn,
26808 * @class Roo.Toolbar.Spacer
26809 * @extends Roo.Toolbar.Item
26810 * A simple element that adds extra horizontal space to a toolbar.
26812 * Creates a new Spacer
26814 Roo.Toolbar.Spacer = function(){
26815 var s = document.createElement("div");
26816 s.className = "ytb-spacer";
26817 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
26819 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
26820 enable:Roo.emptyFn,
26821 disable:Roo.emptyFn,
26826 * @class Roo.Toolbar.Fill
26827 * @extends Roo.Toolbar.Spacer
26828 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
26830 * Creates a new Spacer
26832 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
26834 render : function(td){
26835 td.style.width = '100%';
26836 Roo.Toolbar.Fill.superclass.render.call(this, td);
26841 * @class Roo.Toolbar.TextItem
26842 * @extends Roo.Toolbar.Item
26843 * A simple class that renders text directly into a toolbar.
26845 * Creates a new TextItem
26846 * @param {String} text
26848 Roo.Toolbar.TextItem = function(text){
26849 if (typeof(text) == 'object') {
26852 var s = document.createElement("span");
26853 s.className = "ytb-text";
26854 s.innerHTML = text;
26855 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
26857 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
26858 enable:Roo.emptyFn,
26859 disable:Roo.emptyFn,
26864 * @class Roo.Toolbar.Button
26865 * @extends Roo.Button
26866 * A button that renders into a toolbar.
26868 * Creates a new Button
26869 * @param {Object} config A standard {@link Roo.Button} config object
26871 Roo.Toolbar.Button = function(config){
26872 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
26874 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
26875 render : function(td){
26877 Roo.Toolbar.Button.superclass.render.call(this, td);
26881 * Removes and destroys this button
26883 destroy : function(){
26884 Roo.Toolbar.Button.superclass.destroy.call(this);
26885 this.td.parentNode.removeChild(this.td);
26889 * Shows this button
26892 this.hidden = false;
26893 this.td.style.display = "";
26897 * Hides this button
26900 this.hidden = true;
26901 this.td.style.display = "none";
26905 * Disables this item
26907 disable : function(){
26908 Roo.fly(this.td).addClass("x-item-disabled");
26909 this.disabled = true;
26913 * Enables this item
26915 enable : function(){
26916 Roo.fly(this.td).removeClass("x-item-disabled");
26917 this.disabled = false;
26920 // backwards compat
26921 Roo.ToolbarButton = Roo.Toolbar.Button;
26924 * @class Roo.Toolbar.SplitButton
26925 * @extends Roo.SplitButton
26926 * A menu button that renders into a toolbar.
26928 * Creates a new SplitButton
26929 * @param {Object} config A standard {@link Roo.SplitButton} config object
26931 Roo.Toolbar.SplitButton = function(config){
26932 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
26934 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
26935 render : function(td){
26937 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
26941 * Removes and destroys this button
26943 destroy : function(){
26944 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
26945 this.td.parentNode.removeChild(this.td);
26949 * Shows this button
26952 this.hidden = false;
26953 this.td.style.display = "";
26957 * Hides this button
26960 this.hidden = true;
26961 this.td.style.display = "none";
26965 // backwards compat
26966 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
26968 * Ext JS Library 1.1.1
26969 * Copyright(c) 2006-2007, Ext JS, LLC.
26971 * Originally Released Under LGPL - original licence link has changed is not relivant.
26974 * <script type="text/javascript">
26978 * @class Roo.PagingToolbar
26979 * @extends Roo.Toolbar
26980 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26982 * Create a new PagingToolbar
26983 * @param {Object} config The config object
26985 Roo.PagingToolbar = function(el, ds, config)
26987 // old args format still supported... - xtype is prefered..
26988 if (typeof(el) == 'object' && el.xtype) {
26989 // created from xtype...
26991 ds = el.dataSource;
26992 el = config.container;
26996 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
26999 this.renderButtons(this.el);
27003 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27005 * @cfg {Roo.data.Store} dataSource
27006 * The underlying data store providing the paged data
27009 * @cfg {String/HTMLElement/Element} container
27010 * container The id or element that will contain the toolbar
27013 * @cfg {Boolean} displayInfo
27014 * True to display the displayMsg (defaults to false)
27017 * @cfg {Number} pageSize
27018 * The number of records to display per page (defaults to 20)
27022 * @cfg {String} displayMsg
27023 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27025 displayMsg : 'Displaying {0} - {1} of {2}',
27027 * @cfg {String} emptyMsg
27028 * The message to display when no records are found (defaults to "No data to display")
27030 emptyMsg : 'No data to display',
27032 * Customizable piece of the default paging text (defaults to "Page")
27035 beforePageText : "Page",
27037 * Customizable piece of the default paging text (defaults to "of %0")
27040 afterPageText : "of {0}",
27042 * Customizable piece of the default paging text (defaults to "First Page")
27045 firstText : "First Page",
27047 * Customizable piece of the default paging text (defaults to "Previous Page")
27050 prevText : "Previous Page",
27052 * Customizable piece of the default paging text (defaults to "Next Page")
27055 nextText : "Next Page",
27057 * Customizable piece of the default paging text (defaults to "Last Page")
27060 lastText : "Last Page",
27062 * Customizable piece of the default paging text (defaults to "Refresh")
27065 refreshText : "Refresh",
27068 renderButtons : function(el){
27069 Roo.PagingToolbar.superclass.render.call(this, el);
27070 this.first = this.addButton({
27071 tooltip: this.firstText,
27072 cls: "x-btn-icon x-grid-page-first",
27074 handler: this.onClick.createDelegate(this, ["first"])
27076 this.prev = this.addButton({
27077 tooltip: this.prevText,
27078 cls: "x-btn-icon x-grid-page-prev",
27080 handler: this.onClick.createDelegate(this, ["prev"])
27082 this.addSeparator();
27083 this.add(this.beforePageText);
27084 this.field = Roo.get(this.addDom({
27089 cls: "x-grid-page-number"
27091 this.field.on("keydown", this.onPagingKeydown, this);
27092 this.field.on("focus", function(){this.dom.select();});
27093 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27094 this.field.setHeight(18);
27095 this.addSeparator();
27096 this.next = this.addButton({
27097 tooltip: this.nextText,
27098 cls: "x-btn-icon x-grid-page-next",
27100 handler: this.onClick.createDelegate(this, ["next"])
27102 this.last = this.addButton({
27103 tooltip: this.lastText,
27104 cls: "x-btn-icon x-grid-page-last",
27106 handler: this.onClick.createDelegate(this, ["last"])
27108 this.addSeparator();
27109 this.loading = this.addButton({
27110 tooltip: this.refreshText,
27111 cls: "x-btn-icon x-grid-loading",
27112 handler: this.onClick.createDelegate(this, ["refresh"])
27115 if(this.displayInfo){
27116 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27121 updateInfo : function(){
27122 if(this.displayEl){
27123 var count = this.ds.getCount();
27124 var msg = count == 0 ?
27128 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27130 this.displayEl.update(msg);
27135 onLoad : function(ds, r, o){
27136 this.cursor = o.params ? o.params.start : 0;
27137 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27139 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27140 this.field.dom.value = ap;
27141 this.first.setDisabled(ap == 1);
27142 this.prev.setDisabled(ap == 1);
27143 this.next.setDisabled(ap == ps);
27144 this.last.setDisabled(ap == ps);
27145 this.loading.enable();
27150 getPageData : function(){
27151 var total = this.ds.getTotalCount();
27154 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27155 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27160 onLoadError : function(){
27161 this.loading.enable();
27165 onPagingKeydown : function(e){
27166 var k = e.getKey();
27167 var d = this.getPageData();
27169 var v = this.field.dom.value, pageNum;
27170 if(!v || isNaN(pageNum = parseInt(v, 10))){
27171 this.field.dom.value = d.activePage;
27174 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27175 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27178 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))
27180 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27181 this.field.dom.value = pageNum;
27182 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27185 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27187 var v = this.field.dom.value, pageNum;
27188 var increment = (e.shiftKey) ? 10 : 1;
27189 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27191 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27192 this.field.dom.value = d.activePage;
27195 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27197 this.field.dom.value = parseInt(v, 10) + increment;
27198 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27199 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27206 beforeLoad : function(){
27208 this.loading.disable();
27213 onClick : function(which){
27217 ds.load({params:{start: 0, limit: this.pageSize}});
27220 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27223 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27226 var total = ds.getTotalCount();
27227 var extra = total % this.pageSize;
27228 var lastStart = extra ? (total - extra) : total-this.pageSize;
27229 ds.load({params:{start: lastStart, limit: this.pageSize}});
27232 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27238 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27239 * @param {Roo.data.Store} store The data store to unbind
27241 unbind : function(ds){
27242 ds.un("beforeload", this.beforeLoad, this);
27243 ds.un("load", this.onLoad, this);
27244 ds.un("loadexception", this.onLoadError, this);
27245 ds.un("remove", this.updateInfo, this);
27246 ds.un("add", this.updateInfo, this);
27247 this.ds = undefined;
27251 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27252 * @param {Roo.data.Store} store The data store to bind
27254 bind : function(ds){
27255 ds.on("beforeload", this.beforeLoad, this);
27256 ds.on("load", this.onLoad, this);
27257 ds.on("loadexception", this.onLoadError, this);
27258 ds.on("remove", this.updateInfo, this);
27259 ds.on("add", this.updateInfo, this);
27264 * Ext JS Library 1.1.1
27265 * Copyright(c) 2006-2007, Ext JS, LLC.
27267 * Originally Released Under LGPL - original licence link has changed is not relivant.
27270 * <script type="text/javascript">
27274 * @class Roo.Resizable
27275 * @extends Roo.util.Observable
27276 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27277 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27278 * 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
27279 * the element will be wrapped for you automatically.</p>
27280 * <p>Here is the list of valid resize handles:</p>
27283 ------ -------------------
27294 * <p>Here's an example showing the creation of a typical Resizable:</p>
27296 var resizer = new Roo.Resizable("element-id", {
27304 resizer.on("resize", myHandler);
27306 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27307 * resizer.east.setDisplayed(false);</p>
27308 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27309 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27310 * resize operation's new size (defaults to [0, 0])
27311 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27312 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27313 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27314 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27315 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27316 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27317 * @cfg {Number} width The width of the element in pixels (defaults to null)
27318 * @cfg {Number} height The height of the element in pixels (defaults to null)
27319 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27320 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27321 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27322 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27323 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27324 * in favor of the handles config option (defaults to false)
27325 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27326 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27327 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27328 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27329 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27330 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27331 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27332 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27333 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27334 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27335 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27337 * Create a new resizable component
27338 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27339 * @param {Object} config configuration options
27341 Roo.Resizable = function(el, config){
27342 this.el = Roo.get(el);
27344 if(config && config.wrap){
27345 config.resizeChild = this.el;
27346 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27347 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27348 this.el.setStyle("overflow", "hidden");
27349 this.el.setPositioning(config.resizeChild.getPositioning());
27350 config.resizeChild.clearPositioning();
27351 if(!config.width || !config.height){
27352 var csize = config.resizeChild.getSize();
27353 this.el.setSize(csize.width, csize.height);
27355 if(config.pinned && !config.adjustments){
27356 config.adjustments = "auto";
27360 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27361 this.proxy.unselectable();
27362 this.proxy.enableDisplayMode('block');
27364 Roo.apply(this, config);
27367 this.disableTrackOver = true;
27368 this.el.addClass("x-resizable-pinned");
27370 // if the element isn't positioned, make it relative
27371 var position = this.el.getStyle("position");
27372 if(position != "absolute" && position != "fixed"){
27373 this.el.setStyle("position", "relative");
27375 if(!this.handles){ // no handles passed, must be legacy style
27376 this.handles = 's,e,se';
27377 if(this.multiDirectional){
27378 this.handles += ',n,w';
27381 if(this.handles == "all"){
27382 this.handles = "n s e w ne nw se sw";
27384 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27385 var ps = Roo.Resizable.positions;
27386 for(var i = 0, len = hs.length; i < len; i++){
27387 if(hs[i] && ps[hs[i]]){
27388 var pos = ps[hs[i]];
27389 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27393 this.corner = this.southeast;
27395 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1){
27396 this.updateBox = true;
27399 this.activeHandle = null;
27401 if(this.resizeChild){
27402 if(typeof this.resizeChild == "boolean"){
27403 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27405 this.resizeChild = Roo.get(this.resizeChild, true);
27409 if(this.adjustments == "auto"){
27410 var rc = this.resizeChild;
27411 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27412 if(rc && (hw || hn)){
27413 rc.position("relative");
27414 rc.setLeft(hw ? hw.el.getWidth() : 0);
27415 rc.setTop(hn ? hn.el.getHeight() : 0);
27417 this.adjustments = [
27418 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27419 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27423 if(this.draggable){
27424 this.dd = this.dynamic ?
27425 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27426 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27432 * @event beforeresize
27433 * Fired before resize is allowed. Set enabled to false to cancel resize.
27434 * @param {Roo.Resizable} this
27435 * @param {Roo.EventObject} e The mousedown event
27437 "beforeresize" : true,
27440 * Fired after a resize.
27441 * @param {Roo.Resizable} this
27442 * @param {Number} width The new width
27443 * @param {Number} height The new height
27444 * @param {Roo.EventObject} e The mouseup event
27449 if(this.width !== null && this.height !== null){
27450 this.resizeTo(this.width, this.height);
27452 this.updateChildSize();
27455 this.el.dom.style.zoom = 1;
27457 Roo.Resizable.superclass.constructor.call(this);
27460 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27461 resizeChild : false,
27462 adjustments : [0, 0],
27472 multiDirectional : false,
27473 disableTrackOver : false,
27474 easing : 'easeOutStrong',
27475 widthIncrement : 0,
27476 heightIncrement : 0,
27480 preserveRatio : false,
27481 transparent: false,
27487 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27489 constrainTo: undefined,
27491 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27493 resizeRegion: undefined,
27497 * Perform a manual resize
27498 * @param {Number} width
27499 * @param {Number} height
27501 resizeTo : function(width, height){
27502 this.el.setSize(width, height);
27503 this.updateChildSize();
27504 this.fireEvent("resize", this, width, height, null);
27508 startSizing : function(e, handle){
27509 this.fireEvent("beforeresize", this, e);
27510 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27513 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27514 this.overlay.unselectable();
27515 this.overlay.enableDisplayMode("block");
27516 this.overlay.on("mousemove", this.onMouseMove, this);
27517 this.overlay.on("mouseup", this.onMouseUp, this);
27519 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27521 this.resizing = true;
27522 this.startBox = this.el.getBox();
27523 this.startPoint = e.getXY();
27524 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27525 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27527 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27528 this.overlay.show();
27530 if(this.constrainTo) {
27531 var ct = Roo.get(this.constrainTo);
27532 this.resizeRegion = ct.getRegion().adjust(
27533 ct.getFrameWidth('t'),
27534 ct.getFrameWidth('l'),
27535 -ct.getFrameWidth('b'),
27536 -ct.getFrameWidth('r')
27540 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27542 this.proxy.setBox(this.startBox);
27544 this.proxy.setStyle('visibility', 'visible');
27550 onMouseDown : function(handle, e){
27553 this.activeHandle = handle;
27554 this.startSizing(e, handle);
27559 onMouseUp : function(e){
27560 var size = this.resizeElement();
27561 this.resizing = false;
27563 this.overlay.hide();
27565 this.fireEvent("resize", this, size.width, size.height, e);
27569 updateChildSize : function(){
27570 if(this.resizeChild){
27572 var child = this.resizeChild;
27573 var adj = this.adjustments;
27574 if(el.dom.offsetWidth){
27575 var b = el.getSize(true);
27576 child.setSize(b.width+adj[0], b.height+adj[1]);
27578 // Second call here for IE
27579 // The first call enables instant resizing and
27580 // the second call corrects scroll bars if they
27583 setTimeout(function(){
27584 if(el.dom.offsetWidth){
27585 var b = el.getSize(true);
27586 child.setSize(b.width+adj[0], b.height+adj[1]);
27594 snap : function(value, inc, min){
27595 if(!inc || !value) return value;
27596 var newValue = value;
27597 var m = value % inc;
27600 newValue = value + (inc-m);
27602 newValue = value - m;
27605 return Math.max(min, newValue);
27609 resizeElement : function(){
27610 var box = this.proxy.getBox();
27611 if(this.updateBox){
27612 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27614 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27616 this.updateChildSize();
27624 constrain : function(v, diff, m, mx){
27627 }else if(v - diff > mx){
27634 onMouseMove : function(e){
27636 try{// try catch so if something goes wrong the user doesn't get hung
27638 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27642 //var curXY = this.startPoint;
27643 var curSize = this.curSize || this.startBox;
27644 var x = this.startBox.x, y = this.startBox.y;
27645 var ox = x, oy = y;
27646 var w = curSize.width, h = curSize.height;
27647 var ow = w, oh = h;
27648 var mw = this.minWidth, mh = this.minHeight;
27649 var mxw = this.maxWidth, mxh = this.maxHeight;
27650 var wi = this.widthIncrement;
27651 var hi = this.heightIncrement;
27653 var eventXY = e.getXY();
27654 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27655 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27657 var pos = this.activeHandle.position;
27662 w = Math.min(Math.max(mw, w), mxw);
27666 h = Math.min(Math.max(mh, h), mxh);
27671 w = Math.min(Math.max(mw, w), mxw);
27672 h = Math.min(Math.max(mh, h), mxh);
27675 diffY = this.constrain(h, diffY, mh, mxh);
27680 diffX = this.constrain(w, diffX, mw, mxw);
27686 w = Math.min(Math.max(mw, w), mxw);
27687 diffY = this.constrain(h, diffY, mh, mxh);
27692 diffX = this.constrain(w, diffX, mw, mxw);
27693 diffY = this.constrain(h, diffY, mh, mxh);
27700 diffX = this.constrain(w, diffX, mw, mxw);
27702 h = Math.min(Math.max(mh, h), mxh);
27708 var sw = this.snap(w, wi, mw);
27709 var sh = this.snap(h, hi, mh);
27710 if(sw != w || sh != h){
27733 if(this.preserveRatio){
27738 h = Math.min(Math.max(mh, h), mxh);
27743 w = Math.min(Math.max(mw, w), mxw);
27748 w = Math.min(Math.max(mw, w), mxw);
27754 w = Math.min(Math.max(mw, w), mxw);
27760 h = Math.min(Math.max(mh, h), mxh);
27768 h = Math.min(Math.max(mh, h), mxh);
27778 h = Math.min(Math.max(mh, h), mxh);
27786 this.proxy.setBounds(x, y, w, h);
27788 this.resizeElement();
27795 handleOver : function(){
27797 this.el.addClass("x-resizable-over");
27802 handleOut : function(){
27803 if(!this.resizing){
27804 this.el.removeClass("x-resizable-over");
27809 * Returns the element this component is bound to.
27810 * @return {Roo.Element}
27812 getEl : function(){
27817 * Returns the resizeChild element (or null).
27818 * @return {Roo.Element}
27820 getResizeChild : function(){
27821 return this.resizeChild;
27825 * Destroys this resizable. If the element was wrapped and
27826 * removeEl is not true then the element remains.
27827 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
27829 destroy : function(removeEl){
27830 this.proxy.remove();
27832 this.overlay.removeAllListeners();
27833 this.overlay.remove();
27835 var ps = Roo.Resizable.positions;
27837 if(typeof ps[k] != "function" && this[ps[k]]){
27838 var h = this[ps[k]];
27839 h.el.removeAllListeners();
27844 this.el.update("");
27851 // hash to map config positions to true positions
27852 Roo.Resizable.positions = {
27853 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast"
27857 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
27859 // only initialize the template if resizable is used
27860 var tpl = Roo.DomHelper.createTemplate(
27861 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
27864 Roo.Resizable.Handle.prototype.tpl = tpl;
27866 this.position = pos;
27868 this.el = this.tpl.append(rz.el.dom, [this.position], true);
27869 this.el.unselectable();
27871 this.el.setOpacity(0);
27873 this.el.on("mousedown", this.onMouseDown, this);
27874 if(!disableTrackOver){
27875 this.el.on("mouseover", this.onMouseOver, this);
27876 this.el.on("mouseout", this.onMouseOut, this);
27881 Roo.Resizable.Handle.prototype = {
27882 afterResize : function(rz){
27886 onMouseDown : function(e){
27887 this.rz.onMouseDown(this, e);
27890 onMouseOver : function(e){
27891 this.rz.handleOver(this, e);
27894 onMouseOut : function(e){
27895 this.rz.handleOut(this, e);
27899 * Ext JS Library 1.1.1
27900 * Copyright(c) 2006-2007, Ext JS, LLC.
27902 * Originally Released Under LGPL - original licence link has changed is not relivant.
27905 * <script type="text/javascript">
27909 * @class Roo.Editor
27910 * @extends Roo.Component
27911 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
27913 * Create a new Editor
27914 * @param {Roo.form.Field} field The Field object (or descendant)
27915 * @param {Object} config The config object
27917 Roo.Editor = function(field, config){
27918 Roo.Editor.superclass.constructor.call(this, config);
27919 this.field = field;
27922 * @event beforestartedit
27923 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
27924 * false from the handler of this event.
27925 * @param {Editor} this
27926 * @param {Roo.Element} boundEl The underlying element bound to this editor
27927 * @param {Mixed} value The field value being set
27929 "beforestartedit" : true,
27932 * Fires when this editor is displayed
27933 * @param {Roo.Element} boundEl The underlying element bound to this editor
27934 * @param {Mixed} value The starting field value
27936 "startedit" : true,
27938 * @event beforecomplete
27939 * Fires after a change has been made to the field, but before the change is reflected in the underlying
27940 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
27941 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
27942 * event will not fire since no edit actually occurred.
27943 * @param {Editor} this
27944 * @param {Mixed} value The current field value
27945 * @param {Mixed} startValue The original field value
27947 "beforecomplete" : true,
27950 * Fires after editing is complete and any changed value has been written to the underlying field.
27951 * @param {Editor} this
27952 * @param {Mixed} value The current field value
27953 * @param {Mixed} startValue The original field value
27957 * @event specialkey
27958 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
27959 * {@link Roo.EventObject#getKey} to determine which key was pressed.
27960 * @param {Roo.form.Field} this
27961 * @param {Roo.EventObject} e The event object
27963 "specialkey" : true
27967 Roo.extend(Roo.Editor, Roo.Component, {
27969 * @cfg {Boolean/String} autosize
27970 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
27971 * or "height" to adopt the height only (defaults to false)
27974 * @cfg {Boolean} revertInvalid
27975 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
27976 * validation fails (defaults to true)
27979 * @cfg {Boolean} ignoreNoChange
27980 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
27981 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
27982 * will never be ignored.
27985 * @cfg {Boolean} hideEl
27986 * False to keep the bound element visible while the editor is displayed (defaults to true)
27989 * @cfg {Mixed} value
27990 * The data value of the underlying field (defaults to "")
27994 * @cfg {String} alignment
27995 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
27999 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28000 * for bottom-right shadow (defaults to "frame")
28004 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28008 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28010 completeOnEnter : false,
28012 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28014 cancelOnEsc : false,
28016 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28021 onRender : function(ct, position){
28022 this.el = new Roo.Layer({
28023 shadow: this.shadow,
28029 constrain: this.constrain
28031 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28032 if(this.field.msgTarget != 'title'){
28033 this.field.msgTarget = 'qtip';
28035 this.field.render(this.el);
28037 this.field.el.dom.setAttribute('autocomplete', 'off');
28039 this.field.on("specialkey", this.onSpecialKey, this);
28040 if(this.swallowKeys){
28041 this.field.el.swallowEvent(['keydown','keypress']);
28044 this.field.on("blur", this.onBlur, this);
28045 if(this.field.grow){
28046 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28050 onSpecialKey : function(field, e){
28051 if(this.completeOnEnter && e.getKey() == e.ENTER){
28053 this.completeEdit();
28054 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
28057 this.fireEvent('specialkey', field, e);
28062 * Starts the editing process and shows the editor.
28063 * @param {String/HTMLElement/Element} el The element to edit
28064 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28065 * to the innerHTML of el.
28067 startEdit : function(el, value){
28069 this.completeEdit();
28071 this.boundEl = Roo.get(el);
28072 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28073 if(!this.rendered){
28074 this.render(this.parentEl || document.body);
28076 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28079 this.startValue = v;
28080 this.field.setValue(v);
28082 var sz = this.boundEl.getSize();
28083 switch(this.autoSize){
28085 this.setSize(sz.width, "");
28088 this.setSize("", sz.height);
28091 this.setSize(sz.width, sz.height);
28094 this.el.alignTo(this.boundEl, this.alignment);
28095 this.editing = true;
28097 Roo.QuickTips.disable();
28103 * Sets the height and width of this editor.
28104 * @param {Number} width The new width
28105 * @param {Number} height The new height
28107 setSize : function(w, h){
28108 this.field.setSize(w, h);
28115 * Realigns the editor to the bound field based on the current alignment config value.
28117 realign : function(){
28118 this.el.alignTo(this.boundEl, this.alignment);
28122 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28123 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28125 completeEdit : function(remainVisible){
28129 var v = this.getValue();
28130 if(this.revertInvalid !== false && !this.field.isValid()){
28131 v = this.startValue;
28132 this.cancelEdit(true);
28134 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28135 this.editing = false;
28139 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28140 this.editing = false;
28141 if(this.updateEl && this.boundEl){
28142 this.boundEl.update(v);
28144 if(remainVisible !== true){
28147 this.fireEvent("complete", this, v, this.startValue);
28152 onShow : function(){
28154 if(this.hideEl !== false){
28155 this.boundEl.hide();
28158 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28159 this.fixIEFocus = true;
28160 this.deferredFocus.defer(50, this);
28162 this.field.focus();
28164 this.fireEvent("startedit", this.boundEl, this.startValue);
28167 deferredFocus : function(){
28169 this.field.focus();
28174 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28175 * reverted to the original starting value.
28176 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28177 * cancel (defaults to false)
28179 cancelEdit : function(remainVisible){
28181 this.setValue(this.startValue);
28182 if(remainVisible !== true){
28189 onBlur : function(){
28190 if(this.allowBlur !== true && this.editing){
28191 this.completeEdit();
28196 onHide : function(){
28198 this.completeEdit();
28202 if(this.field.collapse){
28203 this.field.collapse();
28206 if(this.hideEl !== false){
28207 this.boundEl.show();
28210 Roo.QuickTips.enable();
28215 * Sets the data value of the editor
28216 * @param {Mixed} value Any valid value supported by the underlying field
28218 setValue : function(v){
28219 this.field.setValue(v);
28223 * Gets the data value of the editor
28224 * @return {Mixed} The data value
28226 getValue : function(){
28227 return this.field.getValue();
28231 * Ext JS Library 1.1.1
28232 * Copyright(c) 2006-2007, Ext JS, LLC.
28234 * Originally Released Under LGPL - original licence link has changed is not relivant.
28237 * <script type="text/javascript">
28241 * @class Roo.BasicDialog
28242 * @extends Roo.util.Observable
28243 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28245 var dlg = new Roo.BasicDialog("my-dlg", {
28254 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28255 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28256 dlg.addButton('Cancel', dlg.hide, dlg);
28259 <b>A Dialog should always be a direct child of the body element.</b>
28260 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28261 * @cfg {String} title Default text to display in the title bar (defaults to null)
28262 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28263 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28264 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28265 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28266 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28267 * (defaults to null with no animation)
28268 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28269 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28270 * property for valid values (defaults to 'all')
28271 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28272 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28273 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28274 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28275 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28276 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28277 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28278 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28279 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28280 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28281 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28282 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28283 * draggable = true (defaults to false)
28284 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28285 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28286 * shadow (defaults to false)
28287 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28288 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28289 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28290 * @cfg {Array} buttons Array of buttons
28291 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28293 * Create a new BasicDialog.
28294 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28295 * @param {Object} config Configuration options
28297 Roo.BasicDialog = function(el, config){
28298 this.el = Roo.get(el);
28299 var dh = Roo.DomHelper;
28300 if(!this.el && config && config.autoCreate){
28301 if(typeof config.autoCreate == "object"){
28302 if(!config.autoCreate.id){
28303 config.autoCreate.id = el;
28305 this.el = dh.append(document.body,
28306 config.autoCreate, true);
28308 this.el = dh.append(document.body,
28309 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28313 el.setDisplayed(true);
28314 el.hide = this.hideAction;
28316 el.addClass("x-dlg");
28318 Roo.apply(this, config);
28320 this.proxy = el.createProxy("x-dlg-proxy");
28321 this.proxy.hide = this.hideAction;
28322 this.proxy.setOpacity(.5);
28326 el.setWidth(config.width);
28329 el.setHeight(config.height);
28331 this.size = el.getSize();
28332 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28333 this.xy = [config.x,config.y];
28335 this.xy = el.getCenterXY(true);
28337 /** The header element @type Roo.Element */
28338 this.header = el.child("> .x-dlg-hd");
28339 /** The body element @type Roo.Element */
28340 this.body = el.child("> .x-dlg-bd");
28341 /** The footer element @type Roo.Element */
28342 this.footer = el.child("> .x-dlg-ft");
28345 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28348 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28351 this.header.unselectable();
28353 this.header.update(this.title);
28355 // this element allows the dialog to be focused for keyboard event
28356 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28357 this.focusEl.swallowEvent("click", true);
28359 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28361 // wrap the body and footer for special rendering
28362 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28364 this.bwrap.dom.appendChild(this.footer.dom);
28367 this.bg = this.el.createChild({
28368 tag: "div", cls:"x-dlg-bg",
28369 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28371 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28374 if(this.autoScroll !== false && !this.autoTabs){
28375 this.body.setStyle("overflow", "auto");
28378 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28380 if(this.closable !== false){
28381 this.el.addClass("x-dlg-closable");
28382 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28383 this.close.on("click", this.closeClick, this);
28384 this.close.addClassOnOver("x-dlg-close-over");
28386 if(this.collapsible !== false){
28387 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28388 this.collapseBtn.on("click", this.collapseClick, this);
28389 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28390 this.header.on("dblclick", this.collapseClick, this);
28392 if(this.resizable !== false){
28393 this.el.addClass("x-dlg-resizable");
28394 this.resizer = new Roo.Resizable(el, {
28395 minWidth: this.minWidth || 80,
28396 minHeight:this.minHeight || 80,
28397 handles: this.resizeHandles || "all",
28400 this.resizer.on("beforeresize", this.beforeResize, this);
28401 this.resizer.on("resize", this.onResize, this);
28403 if(this.draggable !== false){
28404 el.addClass("x-dlg-draggable");
28405 if (!this.proxyDrag) {
28406 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28409 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28411 dd.setHandleElId(this.header.id);
28412 dd.endDrag = this.endMove.createDelegate(this);
28413 dd.startDrag = this.startMove.createDelegate(this);
28414 dd.onDrag = this.onDrag.createDelegate(this);
28419 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28420 this.mask.enableDisplayMode("block");
28422 this.el.addClass("x-dlg-modal");
28425 this.shadow = new Roo.Shadow({
28426 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28427 offset : this.shadowOffset
28430 this.shadowOffset = 0;
28432 if(Roo.useShims && this.shim !== false){
28433 this.shim = this.el.createShim();
28434 this.shim.hide = this.hideAction;
28442 if (this.buttons) {
28443 var bts= this.buttons;
28445 Roo.each(bts, function(b) {
28454 * Fires when a key is pressed
28455 * @param {Roo.BasicDialog} this
28456 * @param {Roo.EventObject} e
28461 * Fires when this dialog is moved by the user.
28462 * @param {Roo.BasicDialog} this
28463 * @param {Number} x The new page X
28464 * @param {Number} y The new page Y
28469 * Fires when this dialog is resized by the user.
28470 * @param {Roo.BasicDialog} this
28471 * @param {Number} width The new width
28472 * @param {Number} height The new height
28476 * @event beforehide
28477 * Fires before this dialog is hidden.
28478 * @param {Roo.BasicDialog} this
28480 "beforehide" : true,
28483 * Fires when this dialog is hidden.
28484 * @param {Roo.BasicDialog} this
28488 * @event beforeshow
28489 * Fires before this dialog is shown.
28490 * @param {Roo.BasicDialog} this
28492 "beforeshow" : true,
28495 * Fires when this dialog is shown.
28496 * @param {Roo.BasicDialog} this
28500 el.on("keydown", this.onKeyDown, this);
28501 el.on("mousedown", this.toFront, this);
28502 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28504 Roo.DialogManager.register(this);
28505 Roo.BasicDialog.superclass.constructor.call(this);
28508 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28509 shadowOffset: Roo.isIE ? 6 : 5,
28512 minButtonWidth: 75,
28513 defaultButton: null,
28514 buttonAlign: "right",
28519 * Sets the dialog title text
28520 * @param {String} text The title text to display
28521 * @return {Roo.BasicDialog} this
28523 setTitle : function(text){
28524 this.header.update(text);
28529 closeClick : function(){
28534 collapseClick : function(){
28535 this[this.collapsed ? "expand" : "collapse"]();
28539 * Collapses the dialog to its minimized state (only the title bar is visible).
28540 * Equivalent to the user clicking the collapse dialog button.
28542 collapse : function(){
28543 if(!this.collapsed){
28544 this.collapsed = true;
28545 this.el.addClass("x-dlg-collapsed");
28546 this.restoreHeight = this.el.getHeight();
28547 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28552 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28553 * clicking the expand dialog button.
28555 expand : function(){
28556 if(this.collapsed){
28557 this.collapsed = false;
28558 this.el.removeClass("x-dlg-collapsed");
28559 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28564 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28565 * @return {Roo.TabPanel} The tabs component
28567 initTabs : function(){
28568 var tabs = this.getTabs();
28569 while(tabs.getTab(0)){
28572 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28574 tabs.addTab(Roo.id(dom), dom.title);
28582 beforeResize : function(){
28583 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28587 onResize : function(){
28588 this.refreshSize();
28589 this.syncBodyHeight();
28590 this.adjustAssets();
28592 this.fireEvent("resize", this, this.size.width, this.size.height);
28596 onKeyDown : function(e){
28597 if(this.isVisible()){
28598 this.fireEvent("keydown", this, e);
28603 * Resizes the dialog.
28604 * @param {Number} width
28605 * @param {Number} height
28606 * @return {Roo.BasicDialog} this
28608 resizeTo : function(width, height){
28609 this.el.setSize(width, height);
28610 this.size = {width: width, height: height};
28611 this.syncBodyHeight();
28612 if(this.fixedcenter){
28615 if(this.isVisible()){
28616 this.constrainXY();
28617 this.adjustAssets();
28619 this.fireEvent("resize", this, width, height);
28625 * Resizes the dialog to fit the specified content size.
28626 * @param {Number} width
28627 * @param {Number} height
28628 * @return {Roo.BasicDialog} this
28630 setContentSize : function(w, h){
28631 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28632 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28633 //if(!this.el.isBorderBox()){
28634 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28635 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28638 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28639 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28641 this.resizeTo(w, h);
28646 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28647 * executed in response to a particular key being pressed while the dialog is active.
28648 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28649 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28650 * @param {Function} fn The function to call
28651 * @param {Object} scope (optional) The scope of the function
28652 * @return {Roo.BasicDialog} this
28654 addKeyListener : function(key, fn, scope){
28655 var keyCode, shift, ctrl, alt;
28656 if(typeof key == "object" && !(key instanceof Array)){
28657 keyCode = key["key"];
28658 shift = key["shift"];
28659 ctrl = key["ctrl"];
28664 var handler = function(dlg, e){
28665 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28666 var k = e.getKey();
28667 if(keyCode instanceof Array){
28668 for(var i = 0, len = keyCode.length; i < len; i++){
28669 if(keyCode[i] == k){
28670 fn.call(scope || window, dlg, k, e);
28676 fn.call(scope || window, dlg, k, e);
28681 this.on("keydown", handler);
28686 * Returns the TabPanel component (creates it if it doesn't exist).
28687 * Note: If you wish to simply check for the existence of tabs without creating them,
28688 * check for a null 'tabs' property.
28689 * @return {Roo.TabPanel} The tabs component
28691 getTabs : function(){
28693 this.el.addClass("x-dlg-auto-tabs");
28694 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28695 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28701 * Adds a button to the footer section of the dialog.
28702 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28703 * object or a valid Roo.DomHelper element config
28704 * @param {Function} handler The function called when the button is clicked
28705 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28706 * @return {Roo.Button} The new button
28708 addButton : function(config, handler, scope){
28709 var dh = Roo.DomHelper;
28711 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28713 if(!this.btnContainer){
28714 var tb = this.footer.createChild({
28716 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28717 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28719 this.btnContainer = tb.firstChild.firstChild.firstChild;
28724 minWidth: this.minButtonWidth,
28727 if(typeof config == "string"){
28728 bconfig.text = config;
28731 bconfig.dhconfig = config;
28733 Roo.apply(bconfig, config);
28737 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28738 bconfig.position = Math.max(0, bconfig.position);
28739 fc = this.btnContainer.childNodes[bconfig.position];
28742 var btn = new Roo.Button(
28744 this.btnContainer.insertBefore(document.createElement("td"),fc)
28745 : this.btnContainer.appendChild(document.createElement("td")),
28746 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
28749 this.syncBodyHeight();
28752 * Array of all the buttons that have been added to this dialog via addButton
28757 this.buttons.push(btn);
28762 * Sets the default button to be focused when the dialog is displayed.
28763 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
28764 * @return {Roo.BasicDialog} this
28766 setDefaultButton : function(btn){
28767 this.defaultButton = btn;
28772 getHeaderFooterHeight : function(safe){
28775 height += this.header.getHeight();
28778 var fm = this.footer.getMargins();
28779 height += (this.footer.getHeight()+fm.top+fm.bottom);
28781 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
28782 height += this.centerBg.getPadding("tb");
28787 syncBodyHeight : function(){
28788 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
28789 var height = this.size.height - this.getHeaderFooterHeight(false);
28790 bd.setHeight(height-bd.getMargins("tb"));
28791 var hh = this.header.getHeight();
28792 var h = this.size.height-hh;
28794 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
28795 bw.setHeight(h-cb.getPadding("tb"));
28796 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
28797 bd.setWidth(bw.getWidth(true));
28799 this.tabs.syncHeight();
28801 this.tabs.el.repaint();
28807 * Restores the previous state of the dialog if Roo.state is configured.
28808 * @return {Roo.BasicDialog} this
28810 restoreState : function(){
28811 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
28812 if(box && box.width){
28813 this.xy = [box.x, box.y];
28814 this.resizeTo(box.width, box.height);
28820 beforeShow : function(){
28822 if(this.fixedcenter){
28823 this.xy = this.el.getCenterXY(true);
28826 Roo.get(document.body).addClass("x-body-masked");
28827 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28830 this.constrainXY();
28834 animShow : function(){
28835 var b = Roo.get(this.animateTarget, true).getBox();
28836 this.proxy.setSize(b.width, b.height);
28837 this.proxy.setLocation(b.x, b.y);
28839 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
28840 true, .35, this.showEl.createDelegate(this));
28844 * Shows the dialog.
28845 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
28846 * @return {Roo.BasicDialog} this
28848 show : function(animateTarget){
28849 if (this.fireEvent("beforeshow", this) === false){
28852 if(this.syncHeightBeforeShow){
28853 this.syncBodyHeight();
28854 }else if(this.firstShow){
28855 this.firstShow = false;
28856 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
28858 this.animateTarget = animateTarget || this.animateTarget;
28859 if(!this.el.isVisible()){
28861 if(this.animateTarget){
28871 showEl : function(){
28873 this.el.setXY(this.xy);
28875 this.adjustAssets(true);
28878 // IE peekaboo bug - fix found by Dave Fenwick
28882 this.fireEvent("show", this);
28886 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
28887 * dialog itself will receive focus.
28889 focus : function(){
28890 if(this.defaultButton){
28891 this.defaultButton.focus();
28893 this.focusEl.focus();
28898 constrainXY : function(){
28899 if(this.constraintoviewport !== false){
28900 if(!this.viewSize){
28901 if(this.container){
28902 var s = this.container.getSize();
28903 this.viewSize = [s.width, s.height];
28905 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
28908 var s = Roo.get(this.container||document).getScroll();
28910 var x = this.xy[0], y = this.xy[1];
28911 var w = this.size.width, h = this.size.height;
28912 var vw = this.viewSize[0], vh = this.viewSize[1];
28913 // only move it if it needs it
28915 // first validate right/bottom
28916 if(x + w > vw+s.left){
28920 if(y + h > vh+s.top){
28924 // then make sure top/left isn't negative
28936 if(this.isVisible()){
28937 this.el.setLocation(x, y);
28938 this.adjustAssets();
28945 onDrag : function(){
28946 if(!this.proxyDrag){
28947 this.xy = this.el.getXY();
28948 this.adjustAssets();
28953 adjustAssets : function(doShow){
28954 var x = this.xy[0], y = this.xy[1];
28955 var w = this.size.width, h = this.size.height;
28956 if(doShow === true){
28958 this.shadow.show(this.el);
28964 if(this.shadow && this.shadow.isVisible()){
28965 this.shadow.show(this.el);
28967 if(this.shim && this.shim.isVisible()){
28968 this.shim.setBounds(x, y, w, h);
28973 adjustViewport : function(w, h){
28975 w = Roo.lib.Dom.getViewWidth();
28976 h = Roo.lib.Dom.getViewHeight();
28979 this.viewSize = [w, h];
28980 if(this.modal && this.mask.isVisible()){
28981 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
28982 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28984 if(this.isVisible()){
28985 this.constrainXY();
28990 * Destroys this dialog and all its supporting elements (including any tabs, shim,
28991 * shadow, proxy, mask, etc.) Also removes all event listeners.
28992 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28994 destroy : function(removeEl){
28995 if(this.isVisible()){
28996 this.animateTarget = null;
28999 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29001 this.tabs.destroy(removeEl);
29014 for(var i = 0, len = this.buttons.length; i < len; i++){
29015 this.buttons[i].destroy();
29018 this.el.removeAllListeners();
29019 if(removeEl === true){
29020 this.el.update("");
29023 Roo.DialogManager.unregister(this);
29027 startMove : function(){
29028 if(this.proxyDrag){
29031 if(this.constraintoviewport !== false){
29032 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29037 endMove : function(){
29038 if(!this.proxyDrag){
29039 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29041 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29044 this.refreshSize();
29045 this.adjustAssets();
29047 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29051 * Brings this dialog to the front of any other visible dialogs
29052 * @return {Roo.BasicDialog} this
29054 toFront : function(){
29055 Roo.DialogManager.bringToFront(this);
29060 * Sends this dialog to the back (under) of any other visible dialogs
29061 * @return {Roo.BasicDialog} this
29063 toBack : function(){
29064 Roo.DialogManager.sendToBack(this);
29069 * Centers this dialog in the viewport
29070 * @return {Roo.BasicDialog} this
29072 center : function(){
29073 var xy = this.el.getCenterXY(true);
29074 this.moveTo(xy[0], xy[1]);
29079 * Moves the dialog's top-left corner to the specified point
29080 * @param {Number} x
29081 * @param {Number} y
29082 * @return {Roo.BasicDialog} this
29084 moveTo : function(x, y){
29086 if(this.isVisible()){
29087 this.el.setXY(this.xy);
29088 this.adjustAssets();
29094 * Aligns the dialog to the specified element
29095 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29096 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29097 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29098 * @return {Roo.BasicDialog} this
29100 alignTo : function(element, position, offsets){
29101 this.xy = this.el.getAlignToXY(element, position, offsets);
29102 if(this.isVisible()){
29103 this.el.setXY(this.xy);
29104 this.adjustAssets();
29110 * Anchors an element to another element and realigns it when the window is resized.
29111 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29112 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29113 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29114 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29115 * is a number, it is used as the buffer delay (defaults to 50ms).
29116 * @return {Roo.BasicDialog} this
29118 anchorTo : function(el, alignment, offsets, monitorScroll){
29119 var action = function(){
29120 this.alignTo(el, alignment, offsets);
29122 Roo.EventManager.onWindowResize(action, this);
29123 var tm = typeof monitorScroll;
29124 if(tm != 'undefined'){
29125 Roo.EventManager.on(window, 'scroll', action, this,
29126 {buffer: tm == 'number' ? monitorScroll : 50});
29133 * Returns true if the dialog is visible
29134 * @return {Boolean}
29136 isVisible : function(){
29137 return this.el.isVisible();
29141 animHide : function(callback){
29142 var b = Roo.get(this.animateTarget).getBox();
29144 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29146 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29147 this.hideEl.createDelegate(this, [callback]));
29151 * Hides the dialog.
29152 * @param {Function} callback (optional) Function to call when the dialog is hidden
29153 * @return {Roo.BasicDialog} this
29155 hide : function(callback){
29156 if (this.fireEvent("beforehide", this) === false){
29160 this.shadow.hide();
29165 if(this.animateTarget){
29166 this.animHide(callback);
29169 this.hideEl(callback);
29175 hideEl : function(callback){
29179 Roo.get(document.body).removeClass("x-body-masked");
29181 this.fireEvent("hide", this);
29182 if(typeof callback == "function"){
29188 hideAction : function(){
29189 this.setLeft("-10000px");
29190 this.setTop("-10000px");
29191 this.setStyle("visibility", "hidden");
29195 refreshSize : function(){
29196 this.size = this.el.getSize();
29197 this.xy = this.el.getXY();
29198 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29202 // z-index is managed by the DialogManager and may be overwritten at any time
29203 setZIndex : function(index){
29205 this.mask.setStyle("z-index", index);
29208 this.shim.setStyle("z-index", ++index);
29211 this.shadow.setZIndex(++index);
29213 this.el.setStyle("z-index", ++index);
29215 this.proxy.setStyle("z-index", ++index);
29218 this.resizer.proxy.setStyle("z-index", ++index);
29221 this.lastZIndex = index;
29225 * Returns the element for this dialog
29226 * @return {Roo.Element} The underlying dialog Element
29228 getEl : function(){
29234 * @class Roo.DialogManager
29235 * Provides global access to BasicDialogs that have been created and
29236 * support for z-indexing (layering) multiple open dialogs.
29238 Roo.DialogManager = function(){
29240 var accessList = [];
29244 var sortDialogs = function(d1, d2){
29245 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29249 var orderDialogs = function(){
29250 accessList.sort(sortDialogs);
29251 var seed = Roo.DialogManager.zseed;
29252 for(var i = 0, len = accessList.length; i < len; i++){
29253 var dlg = accessList[i];
29255 dlg.setZIndex(seed + (i*10));
29262 * The starting z-index for BasicDialogs (defaults to 9000)
29263 * @type Number The z-index value
29268 register : function(dlg){
29269 list[dlg.id] = dlg;
29270 accessList.push(dlg);
29274 unregister : function(dlg){
29275 delete list[dlg.id];
29278 if(!accessList.indexOf){
29279 for( i = 0, len = accessList.length; i < len; i++){
29280 if(accessList[i] == dlg){
29281 accessList.splice(i, 1);
29286 i = accessList.indexOf(dlg);
29288 accessList.splice(i, 1);
29294 * Gets a registered dialog by id
29295 * @param {String/Object} id The id of the dialog or a dialog
29296 * @return {Roo.BasicDialog} this
29298 get : function(id){
29299 return typeof id == "object" ? id : list[id];
29303 * Brings the specified dialog to the front
29304 * @param {String/Object} dlg The id of the dialog or a dialog
29305 * @return {Roo.BasicDialog} this
29307 bringToFront : function(dlg){
29308 dlg = this.get(dlg);
29311 dlg._lastAccess = new Date().getTime();
29318 * Sends the specified dialog to the back
29319 * @param {String/Object} dlg The id of the dialog or a dialog
29320 * @return {Roo.BasicDialog} this
29322 sendToBack : function(dlg){
29323 dlg = this.get(dlg);
29324 dlg._lastAccess = -(new Date().getTime());
29330 * Hides all dialogs
29332 hideAll : function(){
29333 for(var id in list){
29334 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29343 * @class Roo.LayoutDialog
29344 * @extends Roo.BasicDialog
29345 * Dialog which provides adjustments for working with a layout in a Dialog.
29346 * Add your necessary layout config options to the dialog's config.<br>
29347 * Example usage (including a nested layout):
29350 dialog = new Roo.LayoutDialog("download-dlg", {
29359 // layout config merges with the dialog config
29361 tabPosition: "top",
29362 alwaysShowTabs: true
29365 dialog.addKeyListener(27, dialog.hide, dialog);
29366 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29367 dialog.addButton("Build It!", this.getDownload, this);
29369 // we can even add nested layouts
29370 var innerLayout = new Roo.BorderLayout("dl-inner", {
29380 innerLayout.beginUpdate();
29381 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29382 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29383 innerLayout.endUpdate(true);
29385 var layout = dialog.getLayout();
29386 layout.beginUpdate();
29387 layout.add("center", new Roo.ContentPanel("standard-panel",
29388 {title: "Download the Source", fitToFrame:true}));
29389 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29390 {title: "Build your own roo.js"}));
29391 layout.getRegion("center").showPanel(sp);
29392 layout.endUpdate();
29396 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29397 * @param {Object} config configuration options
29399 Roo.LayoutDialog = function(el, cfg){
29402 if (typeof(cfg) == 'undefined') {
29403 config = Roo.apply({}, el);
29404 el = Roo.get( document.documentElement || document.body).createChild();
29405 //config.autoCreate = true;
29409 config.autoTabs = false;
29410 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29411 this.body.setStyle({overflow:"hidden", position:"relative"});
29412 this.layout = new Roo.BorderLayout(this.body.dom, config);
29413 this.layout.monitorWindowResize = false;
29414 this.el.addClass("x-dlg-auto-layout");
29415 // fix case when center region overwrites center function
29416 this.center = Roo.BasicDialog.prototype.center;
29417 this.on("show", this.layout.layout, this.layout, true);
29418 if (config.items) {
29419 var xitems = config.items;
29420 delete config.items;
29421 Roo.each(xitems, this.addxtype, this);
29426 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29428 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29431 endUpdate : function(){
29432 this.layout.endUpdate();
29436 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29439 beginUpdate : function(){
29440 this.layout.beginUpdate();
29444 * Get the BorderLayout for this dialog
29445 * @return {Roo.BorderLayout}
29447 getLayout : function(){
29448 return this.layout;
29451 showEl : function(){
29452 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29454 this.layout.layout();
29459 // Use the syncHeightBeforeShow config option to control this automatically
29460 syncBodyHeight : function(){
29461 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29462 if(this.layout){this.layout.layout();}
29466 * Add an xtype element (actually adds to the layout.)
29467 * @return {Object} xdata xtype object data.
29470 addxtype : function(c) {
29471 return this.layout.addxtype(c);
29475 * Ext JS Library 1.1.1
29476 * Copyright(c) 2006-2007, Ext JS, LLC.
29478 * Originally Released Under LGPL - original licence link has changed is not relivant.
29481 * <script type="text/javascript">
29485 * @class Roo.MessageBox
29486 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29490 Roo.Msg.alert('Status', 'Changes saved successfully.');
29492 // Prompt for user data:
29493 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29495 // process text value...
29499 // Show a dialog using config options:
29501 title:'Save Changes?',
29502 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29503 buttons: Roo.Msg.YESNOCANCEL,
29510 Roo.MessageBox = function(){
29511 var dlg, opt, mask, waitTimer;
29512 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29513 var buttons, activeTextEl, bwidth;
29516 var handleButton = function(button){
29518 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29522 var handleHide = function(){
29523 if(opt && opt.cls){
29524 dlg.el.removeClass(opt.cls);
29527 Roo.TaskMgr.stop(waitTimer);
29533 var updateButtons = function(b){
29536 buttons["ok"].hide();
29537 buttons["cancel"].hide();
29538 buttons["yes"].hide();
29539 buttons["no"].hide();
29540 dlg.footer.dom.style.display = 'none';
29543 dlg.footer.dom.style.display = '';
29544 for(var k in buttons){
29545 if(typeof buttons[k] != "function"){
29548 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29549 width += buttons[k].el.getWidth()+15;
29559 var handleEsc = function(d, k, e){
29560 if(opt && opt.closable !== false){
29570 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29571 * @return {Roo.BasicDialog} The BasicDialog element
29573 getDialog : function(){
29575 dlg = new Roo.BasicDialog("x-msg-box", {
29580 constraintoviewport:false,
29582 collapsible : false,
29585 width:400, height:100,
29586 buttonAlign:"center",
29587 closeClick : function(){
29588 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29589 handleButton("no");
29591 handleButton("cancel");
29595 dlg.on("hide", handleHide);
29597 dlg.addKeyListener(27, handleEsc);
29599 var bt = this.buttonText;
29600 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29601 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29602 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29603 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29604 bodyEl = dlg.body.createChild({
29606 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>'
29608 msgEl = bodyEl.dom.firstChild;
29609 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29610 textboxEl.enableDisplayMode();
29611 textboxEl.addKeyListener([10,13], function(){
29612 if(dlg.isVisible() && opt && opt.buttons){
29613 if(opt.buttons.ok){
29614 handleButton("ok");
29615 }else if(opt.buttons.yes){
29616 handleButton("yes");
29620 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29621 textareaEl.enableDisplayMode();
29622 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29623 progressEl.enableDisplayMode();
29624 var pf = progressEl.dom.firstChild;
29626 pp = Roo.get(pf.firstChild);
29627 pp.setHeight(pf.offsetHeight);
29635 * Updates the message box body text
29636 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29637 * the XHTML-compliant non-breaking space character '&#160;')
29638 * @return {Roo.MessageBox} This message box
29640 updateText : function(text){
29641 if(!dlg.isVisible() && !opt.width){
29642 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29644 msgEl.innerHTML = text || ' ';
29645 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29646 Math.max(opt.minWidth || this.minWidth, bwidth));
29648 activeTextEl.setWidth(w);
29650 if(dlg.isVisible()){
29651 dlg.fixedcenter = false;
29653 dlg.setContentSize(w, bodyEl.getHeight());
29654 if(dlg.isVisible()){
29655 dlg.fixedcenter = true;
29661 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29662 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29663 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29664 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29665 * @return {Roo.MessageBox} This message box
29667 updateProgress : function(value, text){
29669 this.updateText(text);
29671 if (pp) { // weird bug on my firefox - for some reason this is not defined
29672 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29678 * Returns true if the message box is currently displayed
29679 * @return {Boolean} True if the message box is visible, else false
29681 isVisible : function(){
29682 return dlg && dlg.isVisible();
29686 * Hides the message box if it is displayed
29689 if(this.isVisible()){
29695 * Displays a new message box, or reinitializes an existing message box, based on the config options
29696 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29697 * The following config object properties are supported:
29699 Property Type Description
29700 ---------- --------------- ------------------------------------------------------------------------------------
29701 animEl String/Element An id or Element from which the message box should animate as it opens and
29702 closes (defaults to undefined)
29703 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29704 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29705 closable Boolean False to hide the top-right close button (defaults to true). Note that
29706 progress and wait dialogs will ignore this property and always hide the
29707 close button as they can only be closed programmatically.
29708 cls String A custom CSS class to apply to the message box element
29709 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29710 displayed (defaults to 75)
29711 fn Function A callback function to execute after closing the dialog. The arguments to the
29712 function will be btn (the name of the button that was clicked, if applicable,
29713 e.g. "ok"), and text (the value of the active text field, if applicable).
29714 Progress and wait dialogs will ignore this option since they do not respond to
29715 user actions and can only be closed programmatically, so any required function
29716 should be called by the same code after it closes the dialog.
29717 icon String A CSS class that provides a background image to be used as an icon for
29718 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29719 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29720 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29721 modal Boolean False to allow user interaction with the page while the message box is
29722 displayed (defaults to true)
29723 msg String A string that will replace the existing message box body text (defaults
29724 to the XHTML-compliant non-breaking space character ' ')
29725 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29726 progress Boolean True to display a progress bar (defaults to false)
29727 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29728 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29729 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29730 title String The title text
29731 value String The string value to set into the active textbox element if displayed
29732 wait Boolean True to display a progress bar (defaults to false)
29733 width Number The width of the dialog in pixels
29740 msg: 'Please enter your address:',
29742 buttons: Roo.MessageBox.OKCANCEL,
29745 animEl: 'addAddressBtn'
29748 * @param {Object} config Configuration options
29749 * @return {Roo.MessageBox} This message box
29751 show : function(options){
29752 if(this.isVisible()){
29755 var d = this.getDialog();
29757 d.setTitle(opt.title || " ");
29758 d.close.setDisplayed(opt.closable !== false);
29759 activeTextEl = textboxEl;
29760 opt.prompt = opt.prompt || (opt.multiline ? true : false);
29765 textareaEl.setHeight(typeof opt.multiline == "number" ?
29766 opt.multiline : this.defaultTextHeight);
29767 activeTextEl = textareaEl;
29776 progressEl.setDisplayed(opt.progress === true);
29777 this.updateProgress(0);
29778 activeTextEl.dom.value = opt.value || "";
29780 dlg.setDefaultButton(activeTextEl);
29782 var bs = opt.buttons;
29785 db = buttons["ok"];
29786 }else if(bs && bs.yes){
29787 db = buttons["yes"];
29789 dlg.setDefaultButton(db);
29791 bwidth = updateButtons(opt.buttons);
29792 this.updateText(opt.msg);
29794 d.el.addClass(opt.cls);
29796 d.proxyDrag = opt.proxyDrag === true;
29797 d.modal = opt.modal !== false;
29798 d.mask = opt.modal !== false ? mask : false;
29799 if(!d.isVisible()){
29800 // force it to the end of the z-index stack so it gets a cursor in FF
29801 document.body.appendChild(dlg.el.dom);
29802 d.animateTarget = null;
29803 d.show(options.animEl);
29809 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
29810 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
29811 * and closing the message box when the process is complete.
29812 * @param {String} title The title bar text
29813 * @param {String} msg The message box body text
29814 * @return {Roo.MessageBox} This message box
29816 progress : function(title, msg){
29823 minWidth: this.minProgressWidth,
29830 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
29831 * If a callback function is passed it will be called after the user clicks the button, and the
29832 * id of the button that was clicked will be passed as the only parameter to the callback
29833 * (could also be the top-right close button).
29834 * @param {String} title The title bar text
29835 * @param {String} msg The message box body text
29836 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29837 * @param {Object} scope (optional) The scope of the callback function
29838 * @return {Roo.MessageBox} This message box
29840 alert : function(title, msg, fn, scope){
29853 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
29854 * interaction while waiting for a long-running process to complete that does not have defined intervals.
29855 * You are responsible for closing the message box when the process is complete.
29856 * @param {String} msg The message box body text
29857 * @param {String} title (optional) The title bar text
29858 * @return {Roo.MessageBox} This message box
29860 wait : function(msg, title){
29871 waitTimer = Roo.TaskMgr.start({
29873 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
29881 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
29882 * If a callback function is passed it will be called after the user clicks either button, and the id of the
29883 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
29884 * @param {String} title The title bar text
29885 * @param {String} msg The message box body text
29886 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29887 * @param {Object} scope (optional) The scope of the callback function
29888 * @return {Roo.MessageBox} This message box
29890 confirm : function(title, msg, fn, scope){
29894 buttons: this.YESNO,
29903 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
29904 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
29905 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
29906 * (could also be the top-right close button) and the text that was entered will be passed as the two
29907 * parameters to the callback.
29908 * @param {String} title The title bar text
29909 * @param {String} msg The message box body text
29910 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29911 * @param {Object} scope (optional) The scope of the callback function
29912 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
29913 * property, or the height in pixels to create the textbox (defaults to false / single-line)
29914 * @return {Roo.MessageBox} This message box
29916 prompt : function(title, msg, fn, scope, multiline){
29920 buttons: this.OKCANCEL,
29925 multiline: multiline,
29932 * Button config that displays a single OK button
29937 * Button config that displays Yes and No buttons
29940 YESNO : {yes:true, no:true},
29942 * Button config that displays OK and Cancel buttons
29945 OKCANCEL : {ok:true, cancel:true},
29947 * Button config that displays Yes, No and Cancel buttons
29950 YESNOCANCEL : {yes:true, no:true, cancel:true},
29953 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
29956 defaultTextHeight : 75,
29958 * The maximum width in pixels of the message box (defaults to 600)
29963 * The minimum width in pixels of the message box (defaults to 100)
29968 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
29969 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
29972 minProgressWidth : 250,
29974 * An object containing the default button text strings that can be overriden for localized language support.
29975 * Supported properties are: ok, cancel, yes and no.
29976 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
29989 * Shorthand for {@link Roo.MessageBox}
29991 Roo.Msg = Roo.MessageBox;/*
29993 * Ext JS Library 1.1.1
29994 * Copyright(c) 2006-2007, Ext JS, LLC.
29996 * Originally Released Under LGPL - original licence link has changed is not relivant.
29999 * <script type="text/javascript">
30002 * @class Roo.QuickTips
30003 * Provides attractive and customizable tooltips for any element.
30006 Roo.QuickTips = function(){
30007 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30008 var ce, bd, xy, dd;
30009 var visible = false, disabled = true, inited = false;
30010 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30012 var onOver = function(e){
30016 var t = e.getTarget();
30017 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30020 if(ce && t == ce.el){
30021 clearTimeout(hideProc);
30024 if(t && tagEls[t.id]){
30025 tagEls[t.id].el = t;
30026 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30029 var ttp, et = Roo.fly(t);
30030 var ns = cfg.namespace;
30031 if(tm.interceptTitles && t.title){
30034 t.removeAttribute("title");
30035 e.preventDefault();
30037 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30040 showProc = show.defer(tm.showDelay, tm, [{
30043 width: et.getAttributeNS(ns, cfg.width),
30044 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30045 title: et.getAttributeNS(ns, cfg.title),
30046 cls: et.getAttributeNS(ns, cfg.cls)
30051 var onOut = function(e){
30052 clearTimeout(showProc);
30053 var t = e.getTarget();
30054 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30055 hideProc = setTimeout(hide, tm.hideDelay);
30059 var onMove = function(e){
30065 if(tm.trackMouse && ce){
30070 var onDown = function(e){
30071 clearTimeout(showProc);
30072 clearTimeout(hideProc);
30074 if(tm.hideOnClick){
30077 tm.enable.defer(100, tm);
30082 var getPad = function(){
30083 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30086 var show = function(o){
30090 clearTimeout(dismissProc);
30092 if(removeCls){ // in case manually hidden
30093 el.removeClass(removeCls);
30097 el.addClass(ce.cls);
30098 removeCls = ce.cls;
30101 tipTitle.update(ce.title);
30104 tipTitle.update('');
30107 el.dom.style.width = tm.maxWidth+'px';
30108 //tipBody.dom.style.width = '';
30109 tipBodyText.update(o.text);
30110 var p = getPad(), w = ce.width;
30112 var td = tipBodyText.dom;
30113 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30114 if(aw > tm.maxWidth){
30116 }else if(aw < tm.minWidth){
30122 //tipBody.setWidth(w);
30123 el.setWidth(parseInt(w, 10) + p);
30124 if(ce.autoHide === false){
30125 close.setDisplayed(true);
30130 close.setDisplayed(false);
30136 el.avoidY = xy[1]-18;
30141 el.setStyle("visibility", "visible");
30142 el.fadeIn({callback: afterShow});
30148 var afterShow = function(){
30152 if(tm.autoDismiss && ce.autoHide !== false){
30153 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30158 var hide = function(noanim){
30159 clearTimeout(dismissProc);
30160 clearTimeout(hideProc);
30162 if(el.isVisible()){
30164 if(noanim !== true && tm.animate){
30165 el.fadeOut({callback: afterHide});
30172 var afterHide = function(){
30175 el.removeClass(removeCls);
30182 * @cfg {Number} minWidth
30183 * The minimum width of the quick tip (defaults to 40)
30187 * @cfg {Number} maxWidth
30188 * The maximum width of the quick tip (defaults to 300)
30192 * @cfg {Boolean} interceptTitles
30193 * True to automatically use the element's DOM title value if available (defaults to false)
30195 interceptTitles : false,
30197 * @cfg {Boolean} trackMouse
30198 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30200 trackMouse : false,
30202 * @cfg {Boolean} hideOnClick
30203 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30205 hideOnClick : true,
30207 * @cfg {Number} showDelay
30208 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30212 * @cfg {Number} hideDelay
30213 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30217 * @cfg {Boolean} autoHide
30218 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30219 * Used in conjunction with hideDelay.
30224 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30225 * (defaults to true). Used in conjunction with autoDismissDelay.
30227 autoDismiss : true,
30230 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30232 autoDismissDelay : 5000,
30234 * @cfg {Boolean} animate
30235 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30240 * @cfg {String} title
30241 * Title text to display (defaults to ''). This can be any valid HTML markup.
30245 * @cfg {String} text
30246 * Body text to display (defaults to ''). This can be any valid HTML markup.
30250 * @cfg {String} cls
30251 * A CSS class to apply to the base quick tip element (defaults to '').
30255 * @cfg {Number} width
30256 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30257 * minWidth or maxWidth.
30262 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30263 * or display QuickTips in a page.
30266 tm = Roo.QuickTips;
30267 cfg = tm.tagConfig;
30269 if(!Roo.isReady){ // allow calling of init() before onReady
30270 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30273 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30274 el.fxDefaults = {stopFx: true};
30275 // maximum custom styling
30276 //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>');
30277 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>');
30278 tipTitle = el.child('h3');
30279 tipTitle.enableDisplayMode("block");
30280 tipBody = el.child('div.x-tip-bd');
30281 tipBodyText = el.child('div.x-tip-bd-inner');
30282 //bdLeft = el.child('div.x-tip-bd-left');
30283 //bdRight = el.child('div.x-tip-bd-right');
30284 close = el.child('div.x-tip-close');
30285 close.enableDisplayMode("block");
30286 close.on("click", hide);
30287 var d = Roo.get(document);
30288 d.on("mousedown", onDown);
30289 d.on("mouseover", onOver);
30290 d.on("mouseout", onOut);
30291 d.on("mousemove", onMove);
30292 esc = d.addKeyListener(27, hide);
30295 dd = el.initDD("default", null, {
30296 onDrag : function(){
30300 dd.setHandleElId(tipTitle.id);
30309 * Configures a new quick tip instance and assigns it to a target element. The following config options
30312 Property Type Description
30313 ---------- --------------------- ------------------------------------------------------------------------
30314 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30316 * @param {Object} config The config object
30318 register : function(config){
30319 var cs = config instanceof Array ? config : arguments;
30320 for(var i = 0, len = cs.length; i < len; i++) {
30322 var target = c.target;
30324 if(target instanceof Array){
30325 for(var j = 0, jlen = target.length; j < jlen; j++){
30326 tagEls[target[j]] = c;
30329 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30336 * Removes this quick tip from its element and destroys it.
30337 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30339 unregister : function(el){
30340 delete tagEls[Roo.id(el)];
30344 * Enable this quick tip.
30346 enable : function(){
30347 if(inited && disabled){
30349 if(locks.length < 1){
30356 * Disable this quick tip.
30358 disable : function(){
30360 clearTimeout(showProc);
30361 clearTimeout(hideProc);
30362 clearTimeout(dismissProc);
30370 * Returns true if the quick tip is enabled, else false.
30372 isEnabled : function(){
30379 attribute : "qtip",
30389 // backwards compat
30390 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30392 * Ext JS Library 1.1.1
30393 * Copyright(c) 2006-2007, Ext JS, LLC.
30395 * Originally Released Under LGPL - original licence link has changed is not relivant.
30398 * <script type="text/javascript">
30403 * @class Roo.tree.TreePanel
30404 * @extends Roo.data.Tree
30406 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30407 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30408 * @cfg {Boolean} enableDD true to enable drag and drop
30409 * @cfg {Boolean} enableDrag true to enable just drag
30410 * @cfg {Boolean} enableDrop true to enable just drop
30411 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30412 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30413 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30414 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30415 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30416 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30417 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30418 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30419 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30420 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30421 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30422 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30423 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30424 * @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>
30425 * @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>
30428 * @param {String/HTMLElement/Element} el The container element
30429 * @param {Object} config
30431 Roo.tree.TreePanel = function(el, config){
30433 var loader = false;
30435 root = config.root;
30436 delete config.root;
30438 if (config.loader) {
30439 loader = config.loader;
30440 delete config.loader;
30443 Roo.apply(this, config);
30444 Roo.tree.TreePanel.superclass.constructor.call(this);
30445 this.el = Roo.get(el);
30446 this.el.addClass('x-tree');
30447 //console.log(root);
30449 this.setRootNode( Roo.factory(root, Roo.tree));
30452 this.loader = Roo.factory(loader, Roo.tree);
30455 * Read-only. The id of the container element becomes this TreePanel's id.
30457 this.id = this.el.id;
30460 * @event beforeload
30461 * Fires before a node is loaded, return false to cancel
30462 * @param {Node} node The node being loaded
30464 "beforeload" : true,
30467 * Fires when a node is loaded
30468 * @param {Node} node The node that was loaded
30472 * @event textchange
30473 * Fires when the text for a node is changed
30474 * @param {Node} node The node
30475 * @param {String} text The new text
30476 * @param {String} oldText The old text
30478 "textchange" : true,
30480 * @event beforeexpand
30481 * Fires before a node is expanded, return false to cancel.
30482 * @param {Node} node The node
30483 * @param {Boolean} deep
30484 * @param {Boolean} anim
30486 "beforeexpand" : true,
30488 * @event beforecollapse
30489 * Fires before a node is collapsed, return false to cancel.
30490 * @param {Node} node The node
30491 * @param {Boolean} deep
30492 * @param {Boolean} anim
30494 "beforecollapse" : true,
30497 * Fires when a node is expanded
30498 * @param {Node} node The node
30502 * @event disabledchange
30503 * Fires when the disabled status of a node changes
30504 * @param {Node} node The node
30505 * @param {Boolean} disabled
30507 "disabledchange" : true,
30510 * Fires when a node is collapsed
30511 * @param {Node} node The node
30515 * @event beforeclick
30516 * Fires before click processing on a node. Return false to cancel the default action.
30517 * @param {Node} node The node
30518 * @param {Roo.EventObject} e The event object
30520 "beforeclick":true,
30522 * @event checkchange
30523 * Fires when a node with a checkbox's checked property changes
30524 * @param {Node} this This node
30525 * @param {Boolean} checked
30527 "checkchange":true,
30530 * Fires when a node is clicked
30531 * @param {Node} node The node
30532 * @param {Roo.EventObject} e The event object
30537 * Fires when a node is double clicked
30538 * @param {Node} node The node
30539 * @param {Roo.EventObject} e The event object
30543 * @event contextmenu
30544 * Fires when a node is right clicked
30545 * @param {Node} node The node
30546 * @param {Roo.EventObject} e The event object
30548 "contextmenu":true,
30550 * @event beforechildrenrendered
30551 * Fires right before the child nodes for a node are rendered
30552 * @param {Node} node The node
30554 "beforechildrenrendered":true,
30557 * Fires when a node starts being dragged
30558 * @param {Roo.tree.TreePanel} this
30559 * @param {Roo.tree.TreeNode} node
30560 * @param {event} e The raw browser event
30562 "startdrag" : true,
30565 * Fires when a drag operation is complete
30566 * @param {Roo.tree.TreePanel} this
30567 * @param {Roo.tree.TreeNode} node
30568 * @param {event} e The raw browser event
30573 * Fires when a dragged node is dropped on a valid DD target
30574 * @param {Roo.tree.TreePanel} this
30575 * @param {Roo.tree.TreeNode} node
30576 * @param {DD} dd The dd it was dropped on
30577 * @param {event} e The raw browser event
30581 * @event beforenodedrop
30582 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30583 * passed to handlers has the following properties:<br />
30584 * <ul style="padding:5px;padding-left:16px;">
30585 * <li>tree - The TreePanel</li>
30586 * <li>target - The node being targeted for the drop</li>
30587 * <li>data - The drag data from the drag source</li>
30588 * <li>point - The point of the drop - append, above or below</li>
30589 * <li>source - The drag source</li>
30590 * <li>rawEvent - Raw mouse event</li>
30591 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30592 * to be inserted by setting them on this object.</li>
30593 * <li>cancel - Set this to true to cancel the drop.</li>
30595 * @param {Object} dropEvent
30597 "beforenodedrop" : true,
30600 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30601 * passed to handlers has the following properties:<br />
30602 * <ul style="padding:5px;padding-left:16px;">
30603 * <li>tree - The TreePanel</li>
30604 * <li>target - The node being targeted for the drop</li>
30605 * <li>data - The drag data from the drag source</li>
30606 * <li>point - The point of the drop - append, above or below</li>
30607 * <li>source - The drag source</li>
30608 * <li>rawEvent - Raw mouse event</li>
30609 * <li>dropNode - Dropped node(s).</li>
30611 * @param {Object} dropEvent
30615 * @event nodedragover
30616 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30617 * passed to handlers has the following properties:<br />
30618 * <ul style="padding:5px;padding-left:16px;">
30619 * <li>tree - The TreePanel</li>
30620 * <li>target - The node being targeted for the drop</li>
30621 * <li>data - The drag data from the drag source</li>
30622 * <li>point - The point of the drop - append, above or below</li>
30623 * <li>source - The drag source</li>
30624 * <li>rawEvent - Raw mouse event</li>
30625 * <li>dropNode - Drop node(s) provided by the source.</li>
30626 * <li>cancel - Set this to true to signal drop not allowed.</li>
30628 * @param {Object} dragOverEvent
30630 "nodedragover" : true
30633 if(this.singleExpand){
30634 this.on("beforeexpand", this.restrictExpand, this);
30637 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30638 rootVisible : true,
30639 animate: Roo.enableFx,
30642 hlDrop : Roo.enableFx,
30646 rendererTip: false,
30648 restrictExpand : function(node){
30649 var p = node.parentNode;
30651 if(p.expandedChild && p.expandedChild.parentNode == p){
30652 p.expandedChild.collapse();
30654 p.expandedChild = node;
30658 // private override
30659 setRootNode : function(node){
30660 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30661 if(!this.rootVisible){
30662 node.ui = new Roo.tree.RootTreeNodeUI(node);
30668 * Returns the container element for this TreePanel
30670 getEl : function(){
30675 * Returns the default TreeLoader for this TreePanel
30677 getLoader : function(){
30678 return this.loader;
30684 expandAll : function(){
30685 this.root.expand(true);
30689 * Collapse all nodes
30691 collapseAll : function(){
30692 this.root.collapse(true);
30696 * Returns the selection model used by this TreePanel
30698 getSelectionModel : function(){
30699 if(!this.selModel){
30700 this.selModel = new Roo.tree.DefaultSelectionModel();
30702 return this.selModel;
30706 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30707 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30708 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30711 getChecked : function(a, startNode){
30712 startNode = startNode || this.root;
30714 var f = function(){
30715 if(this.attributes.checked){
30716 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30719 startNode.cascade(f);
30724 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30725 * @param {String} path
30726 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30727 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30728 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30730 expandPath : function(path, attr, callback){
30731 attr = attr || "id";
30732 var keys = path.split(this.pathSeparator);
30733 var curNode = this.root;
30734 if(curNode.attributes[attr] != keys[1]){ // invalid root
30736 callback(false, null);
30741 var f = function(){
30742 if(++index == keys.length){
30744 callback(true, curNode);
30748 var c = curNode.findChild(attr, keys[index]);
30751 callback(false, curNode);
30756 c.expand(false, false, f);
30758 curNode.expand(false, false, f);
30762 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30763 * @param {String} path
30764 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30765 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
30766 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
30768 selectPath : function(path, attr, callback){
30769 attr = attr || "id";
30770 var keys = path.split(this.pathSeparator);
30771 var v = keys.pop();
30772 if(keys.length > 0){
30773 var f = function(success, node){
30774 if(success && node){
30775 var n = node.findChild(attr, v);
30781 }else if(callback){
30782 callback(false, n);
30786 callback(false, n);
30790 this.expandPath(keys.join(this.pathSeparator), attr, f);
30792 this.root.select();
30794 callback(true, this.root);
30799 getTreeEl : function(){
30804 * Trigger rendering of this TreePanel
30806 render : function(){
30807 if (this.innerCt) {
30808 return this; // stop it rendering more than once!!
30811 this.innerCt = this.el.createChild({tag:"ul",
30812 cls:"x-tree-root-ct " +
30813 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
30815 if(this.containerScroll){
30816 Roo.dd.ScrollManager.register(this.el);
30818 if((this.enableDD || this.enableDrop) && !this.dropZone){
30820 * The dropZone used by this tree if drop is enabled
30821 * @type Roo.tree.TreeDropZone
30823 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
30824 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
30827 if((this.enableDD || this.enableDrag) && !this.dragZone){
30829 * The dragZone used by this tree if drag is enabled
30830 * @type Roo.tree.TreeDragZone
30832 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
30833 ddGroup: this.ddGroup || "TreeDD",
30834 scroll: this.ddScroll
30837 this.getSelectionModel().init(this);
30839 console.log("ROOT not set in tree");
30842 this.root.render();
30843 if(!this.rootVisible){
30844 this.root.renderChildren();
30850 * Ext JS Library 1.1.1
30851 * Copyright(c) 2006-2007, Ext JS, LLC.
30853 * Originally Released Under LGPL - original licence link has changed is not relivant.
30856 * <script type="text/javascript">
30861 * @class Roo.tree.DefaultSelectionModel
30862 * @extends Roo.util.Observable
30863 * The default single selection for a TreePanel.
30865 Roo.tree.DefaultSelectionModel = function(){
30866 this.selNode = null;
30870 * @event selectionchange
30871 * Fires when the selected node changes
30872 * @param {DefaultSelectionModel} this
30873 * @param {TreeNode} node the new selection
30875 "selectionchange" : true,
30878 * @event beforeselect
30879 * Fires before the selected node changes, return false to cancel the change
30880 * @param {DefaultSelectionModel} this
30881 * @param {TreeNode} node the new selection
30882 * @param {TreeNode} node the old selection
30884 "beforeselect" : true
30888 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
30889 init : function(tree){
30891 tree.getTreeEl().on("keydown", this.onKeyDown, this);
30892 tree.on("click", this.onNodeClick, this);
30895 onNodeClick : function(node, e){
30896 if (e.ctrlKey && this.selNode == node) {
30897 this.unselect(node);
30905 * @param {TreeNode} node The node to select
30906 * @return {TreeNode} The selected node
30908 select : function(node){
30909 var last = this.selNode;
30910 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
30912 last.ui.onSelectedChange(false);
30914 this.selNode = node;
30915 node.ui.onSelectedChange(true);
30916 this.fireEvent("selectionchange", this, node, last);
30923 * @param {TreeNode} node The node to unselect
30925 unselect : function(node){
30926 if(this.selNode == node){
30927 this.clearSelections();
30932 * Clear all selections
30934 clearSelections : function(){
30935 var n = this.selNode;
30937 n.ui.onSelectedChange(false);
30938 this.selNode = null;
30939 this.fireEvent("selectionchange", this, null);
30945 * Get the selected node
30946 * @return {TreeNode} The selected node
30948 getSelectedNode : function(){
30949 return this.selNode;
30953 * Returns true if the node is selected
30954 * @param {TreeNode} node The node to check
30955 * @return {Boolean}
30957 isSelected : function(node){
30958 return this.selNode == node;
30962 * Selects the node above the selected node in the tree, intelligently walking the nodes
30963 * @return TreeNode The new selection
30965 selectPrevious : function(){
30966 var s = this.selNode || this.lastSelNode;
30970 var ps = s.previousSibling;
30972 if(!ps.isExpanded() || ps.childNodes.length < 1){
30973 return this.select(ps);
30975 var lc = ps.lastChild;
30976 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
30979 return this.select(lc);
30981 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
30982 return this.select(s.parentNode);
30988 * Selects the node above the selected node in the tree, intelligently walking the nodes
30989 * @return TreeNode The new selection
30991 selectNext : function(){
30992 var s = this.selNode || this.lastSelNode;
30996 if(s.firstChild && s.isExpanded()){
30997 return this.select(s.firstChild);
30998 }else if(s.nextSibling){
30999 return this.select(s.nextSibling);
31000 }else if(s.parentNode){
31002 s.parentNode.bubble(function(){
31003 if(this.nextSibling){
31004 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31013 onKeyDown : function(e){
31014 var s = this.selNode || this.lastSelNode;
31015 // undesirable, but required
31020 var k = e.getKey();
31028 this.selectPrevious();
31031 e.preventDefault();
31032 if(s.hasChildNodes()){
31033 if(!s.isExpanded()){
31035 }else if(s.firstChild){
31036 this.select(s.firstChild, e);
31041 e.preventDefault();
31042 if(s.hasChildNodes() && s.isExpanded()){
31044 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31045 this.select(s.parentNode, e);
31053 * @class Roo.tree.MultiSelectionModel
31054 * @extends Roo.util.Observable
31055 * Multi selection for a TreePanel.
31057 Roo.tree.MultiSelectionModel = function(){
31058 this.selNodes = [];
31062 * @event selectionchange
31063 * Fires when the selected nodes change
31064 * @param {MultiSelectionModel} this
31065 * @param {Array} nodes Array of the selected nodes
31067 "selectionchange" : true
31071 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31072 init : function(tree){
31074 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31075 tree.on("click", this.onNodeClick, this);
31078 onNodeClick : function(node, e){
31079 this.select(node, e, e.ctrlKey);
31084 * @param {TreeNode} node The node to select
31085 * @param {EventObject} e (optional) An event associated with the selection
31086 * @param {Boolean} keepExisting True to retain existing selections
31087 * @return {TreeNode} The selected node
31089 select : function(node, e, keepExisting){
31090 if(keepExisting !== true){
31091 this.clearSelections(true);
31093 if(this.isSelected(node)){
31094 this.lastSelNode = node;
31097 this.selNodes.push(node);
31098 this.selMap[node.id] = node;
31099 this.lastSelNode = node;
31100 node.ui.onSelectedChange(true);
31101 this.fireEvent("selectionchange", this, this.selNodes);
31107 * @param {TreeNode} node The node to unselect
31109 unselect : function(node){
31110 if(this.selMap[node.id]){
31111 node.ui.onSelectedChange(false);
31112 var sn = this.selNodes;
31115 index = sn.indexOf(node);
31117 for(var i = 0, len = sn.length; i < len; i++){
31125 this.selNodes.splice(index, 1);
31127 delete this.selMap[node.id];
31128 this.fireEvent("selectionchange", this, this.selNodes);
31133 * Clear all selections
31135 clearSelections : function(suppressEvent){
31136 var sn = this.selNodes;
31138 for(var i = 0, len = sn.length; i < len; i++){
31139 sn[i].ui.onSelectedChange(false);
31141 this.selNodes = [];
31143 if(suppressEvent !== true){
31144 this.fireEvent("selectionchange", this, this.selNodes);
31150 * Returns true if the node is selected
31151 * @param {TreeNode} node The node to check
31152 * @return {Boolean}
31154 isSelected : function(node){
31155 return this.selMap[node.id] ? true : false;
31159 * Returns an array of the selected nodes
31162 getSelectedNodes : function(){
31163 return this.selNodes;
31166 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31168 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31170 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31173 * Ext JS Library 1.1.1
31174 * Copyright(c) 2006-2007, Ext JS, LLC.
31176 * Originally Released Under LGPL - original licence link has changed is not relivant.
31179 * <script type="text/javascript">
31183 * @class Roo.tree.TreeNode
31184 * @extends Roo.data.Node
31185 * @cfg {String} text The text for this node
31186 * @cfg {Boolean} expanded true to start the node expanded
31187 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31188 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31189 * @cfg {Boolean} disabled true to start the node disabled
31190 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31191 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31192 * @cfg {String} cls A css class to be added to the node
31193 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31194 * @cfg {String} href URL of the link used for the node (defaults to #)
31195 * @cfg {String} hrefTarget target frame for the link
31196 * @cfg {String} qtip An Ext QuickTip for the node
31197 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31198 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31199 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31200 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31201 * (defaults to undefined with no checkbox rendered)
31203 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31205 Roo.tree.TreeNode = function(attributes){
31206 attributes = attributes || {};
31207 if(typeof attributes == "string"){
31208 attributes = {text: attributes};
31210 this.childrenRendered = false;
31211 this.rendered = false;
31212 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31213 this.expanded = attributes.expanded === true;
31214 this.isTarget = attributes.isTarget !== false;
31215 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31216 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31219 * Read-only. The text for this node. To change it use setText().
31222 this.text = attributes.text;
31224 * True if this node is disabled.
31227 this.disabled = attributes.disabled === true;
31231 * @event textchange
31232 * Fires when the text for this node is changed
31233 * @param {Node} this This node
31234 * @param {String} text The new text
31235 * @param {String} oldText The old text
31237 "textchange" : true,
31239 * @event beforeexpand
31240 * Fires before this node is expanded, return false to cancel.
31241 * @param {Node} this This node
31242 * @param {Boolean} deep
31243 * @param {Boolean} anim
31245 "beforeexpand" : true,
31247 * @event beforecollapse
31248 * Fires before this node is collapsed, return false to cancel.
31249 * @param {Node} this This node
31250 * @param {Boolean} deep
31251 * @param {Boolean} anim
31253 "beforecollapse" : true,
31256 * Fires when this node is expanded
31257 * @param {Node} this This node
31261 * @event disabledchange
31262 * Fires when the disabled status of this node changes
31263 * @param {Node} this This node
31264 * @param {Boolean} disabled
31266 "disabledchange" : true,
31269 * Fires when this node is collapsed
31270 * @param {Node} this This node
31274 * @event beforeclick
31275 * Fires before click processing. Return false to cancel the default action.
31276 * @param {Node} this This node
31277 * @param {Roo.EventObject} e The event object
31279 "beforeclick":true,
31281 * @event checkchange
31282 * Fires when a node with a checkbox's checked property changes
31283 * @param {Node} this This node
31284 * @param {Boolean} checked
31286 "checkchange":true,
31289 * Fires when this node is clicked
31290 * @param {Node} this This node
31291 * @param {Roo.EventObject} e The event object
31296 * Fires when this node is double clicked
31297 * @param {Node} this This node
31298 * @param {Roo.EventObject} e The event object
31302 * @event contextmenu
31303 * Fires when this node is right clicked
31304 * @param {Node} this This node
31305 * @param {Roo.EventObject} e The event object
31307 "contextmenu":true,
31309 * @event beforechildrenrendered
31310 * Fires right before the child nodes for this node are rendered
31311 * @param {Node} this This node
31313 "beforechildrenrendered":true
31316 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31319 * Read-only. The UI for this node
31322 this.ui = new uiClass(this);
31324 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31325 preventHScroll: true,
31327 * Returns true if this node is expanded
31328 * @return {Boolean}
31330 isExpanded : function(){
31331 return this.expanded;
31335 * Returns the UI object for this node
31336 * @return {TreeNodeUI}
31338 getUI : function(){
31342 // private override
31343 setFirstChild : function(node){
31344 var of = this.firstChild;
31345 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31346 if(this.childrenRendered && of && node != of){
31347 of.renderIndent(true, true);
31350 this.renderIndent(true, true);
31354 // private override
31355 setLastChild : function(node){
31356 var ol = this.lastChild;
31357 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31358 if(this.childrenRendered && ol && node != ol){
31359 ol.renderIndent(true, true);
31362 this.renderIndent(true, true);
31366 // these methods are overridden to provide lazy rendering support
31367 // private override
31368 appendChild : function(){
31369 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31370 if(node && this.childrenRendered){
31373 this.ui.updateExpandIcon();
31377 // private override
31378 removeChild : function(node){
31379 this.ownerTree.getSelectionModel().unselect(node);
31380 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31381 // if it's been rendered remove dom node
31382 if(this.childrenRendered){
31385 if(this.childNodes.length < 1){
31386 this.collapse(false, false);
31388 this.ui.updateExpandIcon();
31390 if(!this.firstChild) {
31391 this.childrenRendered = false;
31396 // private override
31397 insertBefore : function(node, refNode){
31398 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31399 if(newNode && refNode && this.childrenRendered){
31402 this.ui.updateExpandIcon();
31407 * Sets the text for this node
31408 * @param {String} text
31410 setText : function(text){
31411 var oldText = this.text;
31413 this.attributes.text = text;
31414 if(this.rendered){ // event without subscribing
31415 this.ui.onTextChange(this, text, oldText);
31417 this.fireEvent("textchange", this, text, oldText);
31421 * Triggers selection of this node
31423 select : function(){
31424 this.getOwnerTree().getSelectionModel().select(this);
31428 * Triggers deselection of this node
31430 unselect : function(){
31431 this.getOwnerTree().getSelectionModel().unselect(this);
31435 * Returns true if this node is selected
31436 * @return {Boolean}
31438 isSelected : function(){
31439 return this.getOwnerTree().getSelectionModel().isSelected(this);
31443 * Expand this node.
31444 * @param {Boolean} deep (optional) True to expand all children as well
31445 * @param {Boolean} anim (optional) false to cancel the default animation
31446 * @param {Function} callback (optional) A callback to be called when
31447 * expanding this node completes (does not wait for deep expand to complete).
31448 * Called with 1 parameter, this node.
31450 expand : function(deep, anim, callback){
31451 if(!this.expanded){
31452 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31455 if(!this.childrenRendered){
31456 this.renderChildren();
31458 this.expanded = true;
31459 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31460 this.ui.animExpand(function(){
31461 this.fireEvent("expand", this);
31462 if(typeof callback == "function"){
31466 this.expandChildNodes(true);
31468 }.createDelegate(this));
31472 this.fireEvent("expand", this);
31473 if(typeof callback == "function"){
31478 if(typeof callback == "function"){
31483 this.expandChildNodes(true);
31487 isHiddenRoot : function(){
31488 return this.isRoot && !this.getOwnerTree().rootVisible;
31492 * Collapse this node.
31493 * @param {Boolean} deep (optional) True to collapse all children as well
31494 * @param {Boolean} anim (optional) false to cancel the default animation
31496 collapse : function(deep, anim){
31497 if(this.expanded && !this.isHiddenRoot()){
31498 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31501 this.expanded = false;
31502 if((this.getOwnerTree().animate && anim !== false) || anim){
31503 this.ui.animCollapse(function(){
31504 this.fireEvent("collapse", this);
31506 this.collapseChildNodes(true);
31508 }.createDelegate(this));
31511 this.ui.collapse();
31512 this.fireEvent("collapse", this);
31516 var cs = this.childNodes;
31517 for(var i = 0, len = cs.length; i < len; i++) {
31518 cs[i].collapse(true, false);
31524 delayedExpand : function(delay){
31525 if(!this.expandProcId){
31526 this.expandProcId = this.expand.defer(delay, this);
31531 cancelExpand : function(){
31532 if(this.expandProcId){
31533 clearTimeout(this.expandProcId);
31535 this.expandProcId = false;
31539 * Toggles expanded/collapsed state of the node
31541 toggle : function(){
31550 * Ensures all parent nodes are expanded
31552 ensureVisible : function(callback){
31553 var tree = this.getOwnerTree();
31554 tree.expandPath(this.parentNode.getPath(), false, function(){
31555 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31556 Roo.callback(callback);
31557 }.createDelegate(this));
31561 * Expand all child nodes
31562 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31564 expandChildNodes : function(deep){
31565 var cs = this.childNodes;
31566 for(var i = 0, len = cs.length; i < len; i++) {
31567 cs[i].expand(deep);
31572 * Collapse all child nodes
31573 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31575 collapseChildNodes : function(deep){
31576 var cs = this.childNodes;
31577 for(var i = 0, len = cs.length; i < len; i++) {
31578 cs[i].collapse(deep);
31583 * Disables this node
31585 disable : function(){
31586 this.disabled = true;
31588 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31589 this.ui.onDisableChange(this, true);
31591 this.fireEvent("disabledchange", this, true);
31595 * Enables this node
31597 enable : function(){
31598 this.disabled = false;
31599 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31600 this.ui.onDisableChange(this, false);
31602 this.fireEvent("disabledchange", this, false);
31606 renderChildren : function(suppressEvent){
31607 if(suppressEvent !== false){
31608 this.fireEvent("beforechildrenrendered", this);
31610 var cs = this.childNodes;
31611 for(var i = 0, len = cs.length; i < len; i++){
31612 cs[i].render(true);
31614 this.childrenRendered = true;
31618 sort : function(fn, scope){
31619 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31620 if(this.childrenRendered){
31621 var cs = this.childNodes;
31622 for(var i = 0, len = cs.length; i < len; i++){
31623 cs[i].render(true);
31629 render : function(bulkRender){
31630 this.ui.render(bulkRender);
31631 if(!this.rendered){
31632 this.rendered = true;
31634 this.expanded = false;
31635 this.expand(false, false);
31641 renderIndent : function(deep, refresh){
31643 this.ui.childIndent = null;
31645 this.ui.renderIndent();
31646 if(deep === true && this.childrenRendered){
31647 var cs = this.childNodes;
31648 for(var i = 0, len = cs.length; i < len; i++){
31649 cs[i].renderIndent(true, refresh);
31655 * Ext JS Library 1.1.1
31656 * Copyright(c) 2006-2007, Ext JS, LLC.
31658 * Originally Released Under LGPL - original licence link has changed is not relivant.
31661 * <script type="text/javascript">
31665 * @class Roo.tree.AsyncTreeNode
31666 * @extends Roo.tree.TreeNode
31667 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31669 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31671 Roo.tree.AsyncTreeNode = function(config){
31672 this.loaded = false;
31673 this.loading = false;
31674 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31676 * @event beforeload
31677 * Fires before this node is loaded, return false to cancel
31678 * @param {Node} this This node
31680 this.addEvents({'beforeload':true, 'load': true});
31683 * Fires when this node is loaded
31684 * @param {Node} this This node
31687 * The loader used by this node (defaults to using the tree's defined loader)
31692 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31693 expand : function(deep, anim, callback){
31694 if(this.loading){ // if an async load is already running, waiting til it's done
31696 var f = function(){
31697 if(!this.loading){ // done loading
31698 clearInterval(timer);
31699 this.expand(deep, anim, callback);
31701 }.createDelegate(this);
31702 timer = setInterval(f, 200);
31706 if(this.fireEvent("beforeload", this) === false){
31709 this.loading = true;
31710 this.ui.beforeLoad(this);
31711 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31713 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31717 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31721 * Returns true if this node is currently loading
31722 * @return {Boolean}
31724 isLoading : function(){
31725 return this.loading;
31728 loadComplete : function(deep, anim, callback){
31729 this.loading = false;
31730 this.loaded = true;
31731 this.ui.afterLoad(this);
31732 this.fireEvent("load", this);
31733 this.expand(deep, anim, callback);
31737 * Returns true if this node has been loaded
31738 * @return {Boolean}
31740 isLoaded : function(){
31741 return this.loaded;
31744 hasChildNodes : function(){
31745 if(!this.isLeaf() && !this.loaded){
31748 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
31753 * Trigger a reload for this node
31754 * @param {Function} callback
31756 reload : function(callback){
31757 this.collapse(false, false);
31758 while(this.firstChild){
31759 this.removeChild(this.firstChild);
31761 this.childrenRendered = false;
31762 this.loaded = false;
31763 if(this.isHiddenRoot()){
31764 this.expanded = false;
31766 this.expand(false, false, callback);
31770 * Ext JS Library 1.1.1
31771 * Copyright(c) 2006-2007, Ext JS, LLC.
31773 * Originally Released Under LGPL - original licence link has changed is not relivant.
31776 * <script type="text/javascript">
31780 * @class Roo.tree.TreeNodeUI
31782 * @param {Object} node The node to render
31783 * The TreeNode UI implementation is separate from the
31784 * tree implementation. Unless you are customizing the tree UI,
31785 * you should never have to use this directly.
31787 Roo.tree.TreeNodeUI = function(node){
31789 this.rendered = false;
31790 this.animating = false;
31791 this.emptyIcon = Roo.BLANK_IMAGE_URL;
31794 Roo.tree.TreeNodeUI.prototype = {
31795 removeChild : function(node){
31797 this.ctNode.removeChild(node.ui.getEl());
31801 beforeLoad : function(){
31802 this.addClass("x-tree-node-loading");
31805 afterLoad : function(){
31806 this.removeClass("x-tree-node-loading");
31809 onTextChange : function(node, text, oldText){
31811 this.textNode.innerHTML = text;
31815 onDisableChange : function(node, state){
31816 this.disabled = state;
31818 this.addClass("x-tree-node-disabled");
31820 this.removeClass("x-tree-node-disabled");
31824 onSelectedChange : function(state){
31827 this.addClass("x-tree-selected");
31830 this.removeClass("x-tree-selected");
31834 onMove : function(tree, node, oldParent, newParent, index, refNode){
31835 this.childIndent = null;
31837 var targetNode = newParent.ui.getContainer();
31838 if(!targetNode){//target not rendered
31839 this.holder = document.createElement("div");
31840 this.holder.appendChild(this.wrap);
31843 var insertBefore = refNode ? refNode.ui.getEl() : null;
31845 targetNode.insertBefore(this.wrap, insertBefore);
31847 targetNode.appendChild(this.wrap);
31849 this.node.renderIndent(true);
31853 addClass : function(cls){
31855 Roo.fly(this.elNode).addClass(cls);
31859 removeClass : function(cls){
31861 Roo.fly(this.elNode).removeClass(cls);
31865 remove : function(){
31867 this.holder = document.createElement("div");
31868 this.holder.appendChild(this.wrap);
31872 fireEvent : function(){
31873 return this.node.fireEvent.apply(this.node, arguments);
31876 initEvents : function(){
31877 this.node.on("move", this.onMove, this);
31878 var E = Roo.EventManager;
31879 var a = this.anchor;
31881 var el = Roo.fly(a, '_treeui');
31883 if(Roo.isOpera){ // opera render bug ignores the CSS
31884 el.setStyle("text-decoration", "none");
31887 el.on("click", this.onClick, this);
31888 el.on("dblclick", this.onDblClick, this);
31891 Roo.EventManager.on(this.checkbox,
31892 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
31895 el.on("contextmenu", this.onContextMenu, this);
31897 var icon = Roo.fly(this.iconNode);
31898 icon.on("click", this.onClick, this);
31899 icon.on("dblclick", this.onDblClick, this);
31900 icon.on("contextmenu", this.onContextMenu, this);
31901 E.on(this.ecNode, "click", this.ecClick, this, true);
31903 if(this.node.disabled){
31904 this.addClass("x-tree-node-disabled");
31906 if(this.node.hidden){
31907 this.addClass("x-tree-node-disabled");
31909 var ot = this.node.getOwnerTree();
31910 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
31911 if(dd && (!this.node.isRoot || ot.rootVisible)){
31912 Roo.dd.Registry.register(this.elNode, {
31914 handles: this.getDDHandles(),
31920 getDDHandles : function(){
31921 return [this.iconNode, this.textNode];
31926 this.wrap.style.display = "none";
31932 this.wrap.style.display = "";
31936 onContextMenu : function(e){
31937 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
31938 e.preventDefault();
31940 this.fireEvent("contextmenu", this.node, e);
31944 onClick : function(e){
31949 if(this.fireEvent("beforeclick", this.node, e) !== false){
31950 if(!this.disabled && this.node.attributes.href){
31951 this.fireEvent("click", this.node, e);
31954 e.preventDefault();
31959 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
31960 this.node.toggle();
31963 this.fireEvent("click", this.node, e);
31969 onDblClick : function(e){
31970 e.preventDefault();
31975 this.toggleCheck();
31977 if(!this.animating && this.node.hasChildNodes()){
31978 this.node.toggle();
31980 this.fireEvent("dblclick", this.node, e);
31983 onCheckChange : function(){
31984 var checked = this.checkbox.checked;
31985 this.node.attributes.checked = checked;
31986 this.fireEvent('checkchange', this.node, checked);
31989 ecClick : function(e){
31990 if(!this.animating && this.node.hasChildNodes()){
31991 this.node.toggle();
31995 startDrop : function(){
31996 this.dropping = true;
31999 // delayed drop so the click event doesn't get fired on a drop
32000 endDrop : function(){
32001 setTimeout(function(){
32002 this.dropping = false;
32003 }.createDelegate(this), 50);
32006 expand : function(){
32007 this.updateExpandIcon();
32008 this.ctNode.style.display = "";
32011 focus : function(){
32012 if(!this.node.preventHScroll){
32013 try{this.anchor.focus();
32015 }else if(!Roo.isIE){
32017 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32018 var l = noscroll.scrollLeft;
32019 this.anchor.focus();
32020 noscroll.scrollLeft = l;
32025 toggleCheck : function(value){
32026 var cb = this.checkbox;
32028 cb.checked = (value === undefined ? !cb.checked : value);
32034 this.anchor.blur();
32038 animExpand : function(callback){
32039 var ct = Roo.get(this.ctNode);
32041 if(!this.node.hasChildNodes()){
32042 this.updateExpandIcon();
32043 this.ctNode.style.display = "";
32044 Roo.callback(callback);
32047 this.animating = true;
32048 this.updateExpandIcon();
32051 callback : function(){
32052 this.animating = false;
32053 Roo.callback(callback);
32056 duration: this.node.ownerTree.duration || .25
32060 highlight : function(){
32061 var tree = this.node.getOwnerTree();
32062 Roo.fly(this.wrap).highlight(
32063 tree.hlColor || "C3DAF9",
32064 {endColor: tree.hlBaseColor}
32068 collapse : function(){
32069 this.updateExpandIcon();
32070 this.ctNode.style.display = "none";
32073 animCollapse : function(callback){
32074 var ct = Roo.get(this.ctNode);
32075 ct.enableDisplayMode('block');
32078 this.animating = true;
32079 this.updateExpandIcon();
32082 callback : function(){
32083 this.animating = false;
32084 Roo.callback(callback);
32087 duration: this.node.ownerTree.duration || .25
32091 getContainer : function(){
32092 return this.ctNode;
32095 getEl : function(){
32099 appendDDGhost : function(ghostNode){
32100 ghostNode.appendChild(this.elNode.cloneNode(true));
32103 getDDRepairXY : function(){
32104 return Roo.lib.Dom.getXY(this.iconNode);
32107 onRender : function(){
32111 render : function(bulkRender){
32112 var n = this.node, a = n.attributes;
32113 var targetNode = n.parentNode ?
32114 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32116 if(!this.rendered){
32117 this.rendered = true;
32119 this.renderElements(n, a, targetNode, bulkRender);
32122 if(this.textNode.setAttributeNS){
32123 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32125 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32128 this.textNode.setAttribute("ext:qtip", a.qtip);
32130 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32133 }else if(a.qtipCfg){
32134 a.qtipCfg.target = Roo.id(this.textNode);
32135 Roo.QuickTips.register(a.qtipCfg);
32138 if(!this.node.expanded){
32139 this.updateExpandIcon();
32142 if(bulkRender === true) {
32143 targetNode.appendChild(this.wrap);
32148 renderElements : function(n, a, targetNode, bulkRender){
32149 // add some indent caching, this helps performance when rendering a large tree
32150 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32151 var t = n.getOwnerTree();
32152 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32153 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32154 var cb = typeof a.checked == 'boolean';
32155 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32156 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32157 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32158 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32159 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32160 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32161 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32162 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32163 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32164 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32167 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32168 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32169 n.nextSibling.ui.getEl(), buf.join(""));
32171 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32174 this.elNode = this.wrap.childNodes[0];
32175 this.ctNode = this.wrap.childNodes[1];
32176 var cs = this.elNode.childNodes;
32177 this.indentNode = cs[0];
32178 this.ecNode = cs[1];
32179 this.iconNode = cs[2];
32182 this.checkbox = cs[3];
32185 this.anchor = cs[index];
32186 this.textNode = cs[index].firstChild;
32189 getAnchor : function(){
32190 return this.anchor;
32193 getTextEl : function(){
32194 return this.textNode;
32197 getIconEl : function(){
32198 return this.iconNode;
32201 isChecked : function(){
32202 return this.checkbox ? this.checkbox.checked : false;
32205 updateExpandIcon : function(){
32207 var n = this.node, c1, c2;
32208 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32209 var hasChild = n.hasChildNodes();
32213 c1 = "x-tree-node-collapsed";
32214 c2 = "x-tree-node-expanded";
32217 c1 = "x-tree-node-expanded";
32218 c2 = "x-tree-node-collapsed";
32221 this.removeClass("x-tree-node-leaf");
32222 this.wasLeaf = false;
32224 if(this.c1 != c1 || this.c2 != c2){
32225 Roo.fly(this.elNode).replaceClass(c1, c2);
32226 this.c1 = c1; this.c2 = c2;
32230 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32233 this.wasLeaf = true;
32236 var ecc = "x-tree-ec-icon "+cls;
32237 if(this.ecc != ecc){
32238 this.ecNode.className = ecc;
32244 getChildIndent : function(){
32245 if(!this.childIndent){
32249 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32251 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32253 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32258 this.childIndent = buf.join("");
32260 return this.childIndent;
32263 renderIndent : function(){
32266 var p = this.node.parentNode;
32268 indent = p.ui.getChildIndent();
32270 if(this.indentMarkup != indent){ // don't rerender if not required
32271 this.indentNode.innerHTML = indent;
32272 this.indentMarkup = indent;
32274 this.updateExpandIcon();
32279 Roo.tree.RootTreeNodeUI = function(){
32280 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32282 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32283 render : function(){
32284 if(!this.rendered){
32285 var targetNode = this.node.ownerTree.innerCt.dom;
32286 this.node.expanded = true;
32287 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32288 this.wrap = this.ctNode = targetNode.firstChild;
32291 collapse : function(){
32293 expand : function(){
32297 * Ext JS Library 1.1.1
32298 * Copyright(c) 2006-2007, Ext JS, LLC.
32300 * Originally Released Under LGPL - original licence link has changed is not relivant.
32303 * <script type="text/javascript">
32306 * @class Roo.tree.TreeLoader
32307 * @extends Roo.util.Observable
32308 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32309 * nodes from a specified URL. The response must be a javascript Array definition
32310 * who's elements are node definition objects. eg:
32312 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32313 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32316 * A server request is sent, and child nodes are loaded only when a node is expanded.
32317 * The loading node's id is passed to the server under the parameter name "node" to
32318 * enable the server to produce the correct child nodes.
32320 * To pass extra parameters, an event handler may be attached to the "beforeload"
32321 * event, and the parameters specified in the TreeLoader's baseParams property:
32323 myTreeLoader.on("beforeload", function(treeLoader, node) {
32324 this.baseParams.category = node.attributes.category;
32327 * This would pass an HTTP parameter called "category" to the server containing
32328 * the value of the Node's "category" attribute.
32330 * Creates a new Treeloader.
32331 * @param {Object} config A config object containing config properties.
32333 Roo.tree.TreeLoader = function(config){
32334 this.baseParams = {};
32335 this.requestMethod = "POST";
32336 Roo.apply(this, config);
32341 * @event beforeload
32342 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32343 * @param {Object} This TreeLoader object.
32344 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32345 * @param {Object} callback The callback function specified in the {@link #load} call.
32350 * Fires when the node has been successfuly loaded.
32351 * @param {Object} This TreeLoader object.
32352 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32353 * @param {Object} response The response object containing the data from the server.
32357 * @event loadexception
32358 * Fires if the network request failed.
32359 * @param {Object} This TreeLoader object.
32360 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32361 * @param {Object} response The response object containing the data from the server.
32363 loadexception : true,
32366 * Fires before a node is created, enabling you to return custom Node types
32367 * @param {Object} This TreeLoader object.
32368 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32373 Roo.tree.TreeLoader.superclass.constructor.call(this);
32376 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32378 * @cfg {String} dataUrl The URL from which to request a Json string which
32379 * specifies an array of node definition object representing the child nodes
32383 * @cfg {Object} baseParams (optional) An object containing properties which
32384 * specify HTTP parameters to be passed to each request for child nodes.
32387 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32388 * created by this loader. If the attributes sent by the server have an attribute in this object,
32389 * they take priority.
32392 * @cfg {Object} uiProviders (optional) An object containing properties which
32394 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32395 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32396 * <i>uiProvider</i> attribute of a returned child node is a string rather
32397 * than a reference to a TreeNodeUI implementation, this that string value
32398 * is used as a property name in the uiProviders object. You can define the provider named
32399 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32404 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32405 * child nodes before loading.
32407 clearOnLoad : true,
32410 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32411 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32412 * Grid query { data : [ .....] }
32417 * @cfg {String} queryParam (optional)
32418 * Name of the query as it will be passed on the querystring (defaults to 'node')
32419 * eg. the request will be ?node=[id]
32426 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32427 * This is called automatically when a node is expanded, but may be used to reload
32428 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32429 * @param {Roo.tree.TreeNode} node
32430 * @param {Function} callback
32432 load : function(node, callback){
32433 if(this.clearOnLoad){
32434 while(node.firstChild){
32435 node.removeChild(node.firstChild);
32438 if(node.attributes.children){ // preloaded json children
32439 var cs = node.attributes.children;
32440 for(var i = 0, len = cs.length; i < len; i++){
32441 node.appendChild(this.createNode(cs[i]));
32443 if(typeof callback == "function"){
32446 }else if(this.dataUrl){
32447 this.requestData(node, callback);
32451 getParams: function(node){
32452 var buf = [], bp = this.baseParams;
32453 for(var key in bp){
32454 if(typeof bp[key] != "function"){
32455 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32458 var n = this.queryParam === false ? 'node' : this.queryParam;
32459 buf.push(n + "=", encodeURIComponent(node.id));
32460 return buf.join("");
32463 requestData : function(node, callback){
32464 if(this.fireEvent("beforeload", this, node, callback) !== false){
32465 this.transId = Roo.Ajax.request({
32466 method:this.requestMethod,
32467 url: this.dataUrl||this.url,
32468 success: this.handleResponse,
32469 failure: this.handleFailure,
32471 argument: {callback: callback, node: node},
32472 params: this.getParams(node)
32475 // if the load is cancelled, make sure we notify
32476 // the node that we are done
32477 if(typeof callback == "function"){
32483 isLoading : function(){
32484 return this.transId ? true : false;
32487 abort : function(){
32488 if(this.isLoading()){
32489 Roo.Ajax.abort(this.transId);
32494 createNode : function(attr){
32495 // apply baseAttrs, nice idea Corey!
32496 if(this.baseAttrs){
32497 Roo.applyIf(attr, this.baseAttrs);
32499 if(this.applyLoader !== false){
32500 attr.loader = this;
32502 // uiProvider = depreciated..
32504 if(typeof(attr.uiProvider) == 'string'){
32505 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32506 /** eval:var:attr */ eval(attr.uiProvider);
32508 if(typeof(this.uiProviders['default']) != 'undefined') {
32509 attr.uiProvider = this.uiProviders['default'];
32512 this.fireEvent('create', this, attr);
32514 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32516 new Roo.tree.TreeNode(attr) :
32517 new Roo.tree.AsyncTreeNode(attr));
32520 processResponse : function(response, node, callback){
32521 var json = response.responseText;
32524 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32525 if (this.root !== false) {
32529 for(var i = 0, len = o.length; i < len; i++){
32530 var n = this.createNode(o[i]);
32532 node.appendChild(n);
32535 if(typeof callback == "function"){
32536 callback(this, node);
32539 this.handleFailure(response);
32543 handleResponse : function(response){
32544 this.transId = false;
32545 var a = response.argument;
32546 this.processResponse(response, a.node, a.callback);
32547 this.fireEvent("load", this, a.node, response);
32550 handleFailure : function(response){
32551 this.transId = false;
32552 var a = response.argument;
32553 this.fireEvent("loadexception", this, a.node, response);
32554 if(typeof a.callback == "function"){
32555 a.callback(this, a.node);
32560 * Ext JS Library 1.1.1
32561 * Copyright(c) 2006-2007, Ext JS, LLC.
32563 * Originally Released Under LGPL - original licence link has changed is not relivant.
32566 * <script type="text/javascript">
32570 * @class Roo.tree.TreeFilter
32571 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32572 * @param {TreePanel} tree
32573 * @param {Object} config (optional)
32575 Roo.tree.TreeFilter = function(tree, config){
32577 this.filtered = {};
32578 Roo.apply(this, config);
32581 Roo.tree.TreeFilter.prototype = {
32588 * Filter the data by a specific attribute.
32589 * @param {String/RegExp} value Either string that the attribute value
32590 * should start with or a RegExp to test against the attribute
32591 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32592 * @param {TreeNode} startNode (optional) The node to start the filter at.
32594 filter : function(value, attr, startNode){
32595 attr = attr || "text";
32597 if(typeof value == "string"){
32598 var vlen = value.length;
32599 // auto clear empty filter
32600 if(vlen == 0 && this.clearBlank){
32604 value = value.toLowerCase();
32606 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32608 }else if(value.exec){ // regex?
32610 return value.test(n.attributes[attr]);
32613 throw 'Illegal filter type, must be string or regex';
32615 this.filterBy(f, null, startNode);
32619 * Filter by a function. The passed function will be called with each
32620 * node in the tree (or from the startNode). If the function returns true, the node is kept
32621 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32622 * @param {Function} fn The filter function
32623 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32625 filterBy : function(fn, scope, startNode){
32626 startNode = startNode || this.tree.root;
32627 if(this.autoClear){
32630 var af = this.filtered, rv = this.reverse;
32631 var f = function(n){
32632 if(n == startNode){
32638 var m = fn.call(scope || n, n);
32646 startNode.cascade(f);
32649 if(typeof id != "function"){
32651 if(n && n.parentNode){
32652 n.parentNode.removeChild(n);
32660 * Clears the current filter. Note: with the "remove" option
32661 * set a filter cannot be cleared.
32663 clear : function(){
32665 var af = this.filtered;
32667 if(typeof id != "function"){
32674 this.filtered = {};
32679 * Ext JS Library 1.1.1
32680 * Copyright(c) 2006-2007, Ext JS, LLC.
32682 * Originally Released Under LGPL - original licence link has changed is not relivant.
32685 * <script type="text/javascript">
32690 * @class Roo.tree.TreeSorter
32691 * Provides sorting of nodes in a TreePanel
32693 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32694 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32695 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32696 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32697 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32698 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32700 * @param {TreePanel} tree
32701 * @param {Object} config
32703 Roo.tree.TreeSorter = function(tree, config){
32704 Roo.apply(this, config);
32705 tree.on("beforechildrenrendered", this.doSort, this);
32706 tree.on("append", this.updateSort, this);
32707 tree.on("insert", this.updateSort, this);
32709 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32710 var p = this.property || "text";
32711 var sortType = this.sortType;
32712 var fs = this.folderSort;
32713 var cs = this.caseSensitive === true;
32714 var leafAttr = this.leafAttr || 'leaf';
32716 this.sortFn = function(n1, n2){
32718 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32721 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32725 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32726 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32728 return dsc ? +1 : -1;
32730 return dsc ? -1 : +1;
32737 Roo.tree.TreeSorter.prototype = {
32738 doSort : function(node){
32739 node.sort(this.sortFn);
32742 compareNodes : function(n1, n2){
32743 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
32746 updateSort : function(tree, node){
32747 if(node.childrenRendered){
32748 this.doSort.defer(1, this, [node]);
32753 * Ext JS Library 1.1.1
32754 * Copyright(c) 2006-2007, Ext JS, LLC.
32756 * Originally Released Under LGPL - original licence link has changed is not relivant.
32759 * <script type="text/javascript">
32762 if(Roo.dd.DropZone){
32764 Roo.tree.TreeDropZone = function(tree, config){
32765 this.allowParentInsert = false;
32766 this.allowContainerDrop = false;
32767 this.appendOnly = false;
32768 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
32770 this.lastInsertClass = "x-tree-no-status";
32771 this.dragOverData = {};
32774 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
32775 ddGroup : "TreeDD",
32777 expandDelay : 1000,
32779 expandNode : function(node){
32780 if(node.hasChildNodes() && !node.isExpanded()){
32781 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
32785 queueExpand : function(node){
32786 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
32789 cancelExpand : function(){
32790 if(this.expandProcId){
32791 clearTimeout(this.expandProcId);
32792 this.expandProcId = false;
32796 isValidDropPoint : function(n, pt, dd, e, data){
32797 if(!n || !data){ return false; }
32798 var targetNode = n.node;
32799 var dropNode = data.node;
32800 // default drop rules
32801 if(!(targetNode && targetNode.isTarget && pt)){
32804 if(pt == "append" && targetNode.allowChildren === false){
32807 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
32810 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
32813 // reuse the object
32814 var overEvent = this.dragOverData;
32815 overEvent.tree = this.tree;
32816 overEvent.target = targetNode;
32817 overEvent.data = data;
32818 overEvent.point = pt;
32819 overEvent.source = dd;
32820 overEvent.rawEvent = e;
32821 overEvent.dropNode = dropNode;
32822 overEvent.cancel = false;
32823 var result = this.tree.fireEvent("nodedragover", overEvent);
32824 return overEvent.cancel === false && result !== false;
32827 getDropPoint : function(e, n, dd){
32830 return tn.allowChildren !== false ? "append" : false; // always append for root
32832 var dragEl = n.ddel;
32833 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
32834 var y = Roo.lib.Event.getPageY(e);
32835 var noAppend = tn.allowChildren === false || tn.isLeaf();
32836 if(this.appendOnly || tn.parentNode.allowChildren === false){
32837 return noAppend ? false : "append";
32839 var noBelow = false;
32840 if(!this.allowParentInsert){
32841 noBelow = tn.hasChildNodes() && tn.isExpanded();
32843 var q = (b - t) / (noAppend ? 2 : 3);
32844 if(y >= t && y < (t + q)){
32846 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
32853 onNodeEnter : function(n, dd, e, data){
32854 this.cancelExpand();
32857 onNodeOver : function(n, dd, e, data){
32858 var pt = this.getDropPoint(e, n, dd);
32861 // auto node expand check
32862 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
32863 this.queueExpand(node);
32864 }else if(pt != "append"){
32865 this.cancelExpand();
32868 // set the insert point style on the target node
32869 var returnCls = this.dropNotAllowed;
32870 if(this.isValidDropPoint(n, pt, dd, e, data)){
32875 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
32876 cls = "x-tree-drag-insert-above";
32877 }else if(pt == "below"){
32878 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
32879 cls = "x-tree-drag-insert-below";
32881 returnCls = "x-tree-drop-ok-append";
32882 cls = "x-tree-drag-append";
32884 if(this.lastInsertClass != cls){
32885 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
32886 this.lastInsertClass = cls;
32893 onNodeOut : function(n, dd, e, data){
32894 this.cancelExpand();
32895 this.removeDropIndicators(n);
32898 onNodeDrop : function(n, dd, e, data){
32899 var point = this.getDropPoint(e, n, dd);
32900 var targetNode = n.node;
32901 targetNode.ui.startDrop();
32902 if(!this.isValidDropPoint(n, point, dd, e, data)){
32903 targetNode.ui.endDrop();
32906 // first try to find the drop node
32907 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
32910 target: targetNode,
32915 dropNode: dropNode,
32918 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
32919 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
32920 targetNode.ui.endDrop();
32923 // allow target changing
32924 targetNode = dropEvent.target;
32925 if(point == "append" && !targetNode.isExpanded()){
32926 targetNode.expand(false, null, function(){
32927 this.completeDrop(dropEvent);
32928 }.createDelegate(this));
32930 this.completeDrop(dropEvent);
32935 completeDrop : function(de){
32936 var ns = de.dropNode, p = de.point, t = de.target;
32937 if(!(ns instanceof Array)){
32941 for(var i = 0, len = ns.length; i < len; i++){
32944 t.parentNode.insertBefore(n, t);
32945 }else if(p == "below"){
32946 t.parentNode.insertBefore(n, t.nextSibling);
32952 if(this.tree.hlDrop){
32956 this.tree.fireEvent("nodedrop", de);
32959 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
32960 if(this.tree.hlDrop){
32961 dropNode.ui.focus();
32962 dropNode.ui.highlight();
32964 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
32967 getTree : function(){
32971 removeDropIndicators : function(n){
32974 Roo.fly(el).removeClass([
32975 "x-tree-drag-insert-above",
32976 "x-tree-drag-insert-below",
32977 "x-tree-drag-append"]);
32978 this.lastInsertClass = "_noclass";
32982 beforeDragDrop : function(target, e, id){
32983 this.cancelExpand();
32987 afterRepair : function(data){
32988 if(data && Roo.enableFx){
32989 data.node.ui.highlight();
32997 * Ext JS Library 1.1.1
32998 * Copyright(c) 2006-2007, Ext JS, LLC.
33000 * Originally Released Under LGPL - original licence link has changed is not relivant.
33003 * <script type="text/javascript">
33007 if(Roo.dd.DragZone){
33008 Roo.tree.TreeDragZone = function(tree, config){
33009 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33013 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33014 ddGroup : "TreeDD",
33016 onBeforeDrag : function(data, e){
33018 return n && n.draggable && !n.disabled;
33021 onInitDrag : function(e){
33022 var data = this.dragData;
33023 this.tree.getSelectionModel().select(data.node);
33024 this.proxy.update("");
33025 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33026 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33029 getRepairXY : function(e, data){
33030 return data.node.ui.getDDRepairXY();
33033 onEndDrag : function(data, e){
33034 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33037 onValidDrop : function(dd, e, id){
33038 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33042 beforeInvalidDrop : function(e, id){
33043 // this scrolls the original position back into view
33044 var sm = this.tree.getSelectionModel();
33045 sm.clearSelections();
33046 sm.select(this.dragData.node);
33051 * Ext JS Library 1.1.1
33052 * Copyright(c) 2006-2007, Ext JS, LLC.
33054 * Originally Released Under LGPL - original licence link has changed is not relivant.
33057 * <script type="text/javascript">
33060 * @class Roo.tree.TreeEditor
33061 * @extends Roo.Editor
33062 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33063 * as the editor field.
33065 * @param {TreePanel} tree
33066 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33068 Roo.tree.TreeEditor = function(tree, config){
33069 config = config || {};
33070 var field = config.events ? config : new Roo.form.TextField(config);
33071 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33075 tree.on('beforeclick', this.beforeNodeClick, this);
33076 tree.getTreeEl().on('mousedown', this.hide, this);
33077 this.on('complete', this.updateNode, this);
33078 this.on('beforestartedit', this.fitToTree, this);
33079 this.on('startedit', this.bindScroll, this, {delay:10});
33080 this.on('specialkey', this.onSpecialKey, this);
33083 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33085 * @cfg {String} alignment
33086 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33092 * @cfg {Boolean} hideEl
33093 * True to hide the bound element while the editor is displayed (defaults to false)
33097 * @cfg {String} cls
33098 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33100 cls: "x-small-editor x-tree-editor",
33102 * @cfg {Boolean} shim
33103 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33109 * @cfg {Number} maxWidth
33110 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33111 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33112 * scroll and client offsets into account prior to each edit.
33119 fitToTree : function(ed, el){
33120 var td = this.tree.getTreeEl().dom, nd = el.dom;
33121 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33122 td.scrollLeft = nd.offsetLeft;
33126 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33127 this.setSize(w, '');
33131 triggerEdit : function(node){
33132 this.completeEdit();
33133 this.editNode = node;
33134 this.startEdit(node.ui.textNode, node.text);
33138 bindScroll : function(){
33139 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33143 beforeNodeClick : function(node, e){
33144 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33145 this.lastClick = new Date();
33146 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33148 this.triggerEdit(node);
33154 updateNode : function(ed, value){
33155 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33156 this.editNode.setText(value);
33160 onHide : function(){
33161 Roo.tree.TreeEditor.superclass.onHide.call(this);
33163 this.editNode.ui.focus();
33168 onSpecialKey : function(field, e){
33169 var k = e.getKey();
33173 }else if(k == e.ENTER && !e.hasModifier()){
33175 this.completeEdit();
33178 });//<Script type="text/javascript">
33181 * Ext JS Library 1.1.1
33182 * Copyright(c) 2006-2007, Ext JS, LLC.
33184 * Originally Released Under LGPL - original licence link has changed is not relivant.
33187 * <script type="text/javascript">
33191 * Not documented??? - probably should be...
33194 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33195 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33197 renderElements : function(n, a, targetNode, bulkRender){
33198 //consel.log("renderElements?");
33199 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33201 var t = n.getOwnerTree();
33202 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33204 var cols = t.columns;
33205 var bw = t.borderWidth;
33207 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33208 var cb = typeof a.checked == "boolean";
33209 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33210 var colcls = 'x-t-' + tid + '-c0';
33212 '<li class="x-tree-node">',
33215 '<div class="x-tree-node-el ', a.cls,'">',
33217 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33220 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33221 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33222 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33223 (a.icon ? ' x-tree-node-inline-icon' : ''),
33224 (a.iconCls ? ' '+a.iconCls : ''),
33225 '" unselectable="on" />',
33226 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33227 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33229 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33230 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33231 '<span unselectable="on" qtip="' + tx + '">',
33235 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33236 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33239 for(var i = 1, len = cols.length; i < len; i++){
33241 colcls = 'x-t-' + tid + '-c' +i;
33242 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33243 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33244 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33250 '<div class="x-clear"></div></div>',
33251 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33254 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33255 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33256 n.nextSibling.ui.getEl(), buf.join(""));
33258 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33260 var el = this.wrap.firstChild;
33262 this.elNode = el.firstChild;
33263 this.ranchor = el.childNodes[1];
33264 this.ctNode = this.wrap.childNodes[1];
33265 var cs = el.firstChild.childNodes;
33266 this.indentNode = cs[0];
33267 this.ecNode = cs[1];
33268 this.iconNode = cs[2];
33271 this.checkbox = cs[3];
33274 this.anchor = cs[index];
33276 this.textNode = cs[index].firstChild;
33278 //el.on("click", this.onClick, this);
33279 //el.on("dblclick", this.onDblClick, this);
33282 // console.log(this);
33284 initEvents : function(){
33285 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33288 var a = this.ranchor;
33290 var el = Roo.get(a);
33292 if(Roo.isOpera){ // opera render bug ignores the CSS
33293 el.setStyle("text-decoration", "none");
33296 el.on("click", this.onClick, this);
33297 el.on("dblclick", this.onDblClick, this);
33298 el.on("contextmenu", this.onContextMenu, this);
33302 /*onSelectedChange : function(state){
33305 this.addClass("x-tree-selected");
33308 this.removeClass("x-tree-selected");
33311 addClass : function(cls){
33313 Roo.fly(this.elRow).addClass(cls);
33319 removeClass : function(cls){
33321 Roo.fly(this.elRow).removeClass(cls);
33327 });//<Script type="text/javascript">
33331 * Ext JS Library 1.1.1
33332 * Copyright(c) 2006-2007, Ext JS, LLC.
33334 * Originally Released Under LGPL - original licence link has changed is not relivant.
33337 * <script type="text/javascript">
33342 * @class Roo.tree.ColumnTree
33343 * @extends Roo.data.TreePanel
33344 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33345 * @cfg {int} borderWidth compined right/left border allowance
33347 * @param {String/HTMLElement/Element} el The container element
33348 * @param {Object} config
33350 Roo.tree.ColumnTree = function(el, config)
33352 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33356 * Fire this event on a container when it resizes
33357 * @param {int} w Width
33358 * @param {int} h Height
33362 this.on('resize', this.onResize, this);
33365 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33369 borderWidth: Roo.isBorderBox ? 0 : 2,
33372 render : function(){
33373 // add the header.....
33375 Roo.tree.ColumnTree.superclass.render.apply(this);
33377 this.el.addClass('x-column-tree');
33379 this.headers = this.el.createChild(
33380 {cls:'x-tree-headers'},this.innerCt.dom);
33382 var cols = this.columns, c;
33383 var totalWidth = 0;
33385 var len = cols.length;
33386 for(var i = 0; i < len; i++){
33388 totalWidth += c.width;
33389 this.headEls.push(this.headers.createChild({
33390 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33392 cls:'x-tree-hd-text',
33395 style:'width:'+(c.width-this.borderWidth)+'px;'
33398 this.headers.createChild({cls:'x-clear'});
33399 // prevent floats from wrapping when clipped
33400 this.headers.setWidth(totalWidth);
33401 //this.innerCt.setWidth(totalWidth);
33402 this.innerCt.setStyle({ overflow: 'auto' });
33403 this.onResize(this.width, this.height);
33407 onResize : function(w,h)
33412 this.innerCt.setWidth(this.width);
33413 this.innerCt.setHeight(this.height-20);
33416 var cols = this.columns, c;
33417 var totalWidth = 0;
33419 var len = cols.length;
33420 for(var i = 0; i < len; i++){
33422 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33423 // it's the expander..
33424 expEl = this.headEls[i];
33427 totalWidth += c.width;
33431 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33433 this.headers.setWidth(w-20);
33442 * Ext JS Library 1.1.1
33443 * Copyright(c) 2006-2007, Ext JS, LLC.
33445 * Originally Released Under LGPL - original licence link has changed is not relivant.
33448 * <script type="text/javascript">
33452 * @class Roo.menu.Menu
33453 * @extends Roo.util.Observable
33454 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33455 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33457 * Creates a new Menu
33458 * @param {Object} config Configuration options
33460 Roo.menu.Menu = function(config){
33461 Roo.apply(this, config);
33462 this.id = this.id || Roo.id();
33465 * @event beforeshow
33466 * Fires before this menu is displayed
33467 * @param {Roo.menu.Menu} this
33471 * @event beforehide
33472 * Fires before this menu is hidden
33473 * @param {Roo.menu.Menu} this
33478 * Fires after this menu is displayed
33479 * @param {Roo.menu.Menu} this
33484 * Fires after this menu is hidden
33485 * @param {Roo.menu.Menu} this
33490 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33491 * @param {Roo.menu.Menu} this
33492 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33493 * @param {Roo.EventObject} e
33498 * Fires when the mouse is hovering over this menu
33499 * @param {Roo.menu.Menu} this
33500 * @param {Roo.EventObject} e
33501 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33506 * Fires when the mouse exits this menu
33507 * @param {Roo.menu.Menu} this
33508 * @param {Roo.EventObject} e
33509 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33514 * Fires when a menu item contained in this menu is clicked
33515 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33516 * @param {Roo.EventObject} e
33520 if (this.registerMenu) {
33521 Roo.menu.MenuMgr.register(this);
33524 var mis = this.items;
33525 this.items = new Roo.util.MixedCollection();
33527 this.add.apply(this, mis);
33531 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33533 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33537 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33538 * for bottom-right shadow (defaults to "sides")
33542 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33543 * this menu (defaults to "tl-tr?")
33545 subMenuAlign : "tl-tr?",
33547 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33548 * relative to its element of origin (defaults to "tl-bl?")
33550 defaultAlign : "tl-bl?",
33552 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33554 allowOtherMenus : false,
33556 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33558 registerMenu : true,
33563 render : function(){
33567 var el = this.el = new Roo.Layer({
33569 shadow:this.shadow,
33571 parentEl: this.parentEl || document.body,
33575 this.keyNav = new Roo.menu.MenuNav(this);
33578 el.addClass("x-menu-plain");
33581 el.addClass(this.cls);
33583 // generic focus element
33584 this.focusEl = el.createChild({
33585 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33587 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33588 ul.on("click", this.onClick, this);
33589 ul.on("mouseover", this.onMouseOver, this);
33590 ul.on("mouseout", this.onMouseOut, this);
33591 this.items.each(function(item){
33592 var li = document.createElement("li");
33593 li.className = "x-menu-list-item";
33594 ul.dom.appendChild(li);
33595 item.render(li, this);
33602 autoWidth : function(){
33603 var el = this.el, ul = this.ul;
33607 var w = this.width;
33610 }else if(Roo.isIE){
33611 el.setWidth(this.minWidth);
33612 var t = el.dom.offsetWidth; // force recalc
33613 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33618 delayAutoWidth : function(){
33621 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33623 this.awTask.delay(20);
33628 findTargetItem : function(e){
33629 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33630 if(t && t.menuItemId){
33631 return this.items.get(t.menuItemId);
33636 onClick : function(e){
33638 if(t = this.findTargetItem(e)){
33640 this.fireEvent("click", this, t, e);
33645 setActiveItem : function(item, autoExpand){
33646 if(item != this.activeItem){
33647 if(this.activeItem){
33648 this.activeItem.deactivate();
33650 this.activeItem = item;
33651 item.activate(autoExpand);
33652 }else if(autoExpand){
33658 tryActivate : function(start, step){
33659 var items = this.items;
33660 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33661 var item = items.get(i);
33662 if(!item.disabled && item.canActivate){
33663 this.setActiveItem(item, false);
33671 onMouseOver : function(e){
33673 if(t = this.findTargetItem(e)){
33674 if(t.canActivate && !t.disabled){
33675 this.setActiveItem(t, true);
33678 this.fireEvent("mouseover", this, e, t);
33682 onMouseOut : function(e){
33684 if(t = this.findTargetItem(e)){
33685 if(t == this.activeItem && t.shouldDeactivate(e)){
33686 this.activeItem.deactivate();
33687 delete this.activeItem;
33690 this.fireEvent("mouseout", this, e, t);
33694 * Read-only. Returns true if the menu is currently displayed, else false.
33697 isVisible : function(){
33698 return this.el && !this.hidden;
33702 * Displays this menu relative to another element
33703 * @param {String/HTMLElement/Roo.Element} element The element to align to
33704 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33705 * the element (defaults to this.defaultAlign)
33706 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33708 show : function(el, pos, parentMenu){
33709 this.parentMenu = parentMenu;
33713 this.fireEvent("beforeshow", this);
33714 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33718 * Displays this menu at a specific xy position
33719 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33720 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33722 showAt : function(xy, parentMenu, /* private: */_e){
33723 this.parentMenu = parentMenu;
33728 this.fireEvent("beforeshow", this);
33729 xy = this.el.adjustForConstraints(xy);
33733 this.hidden = false;
33735 this.fireEvent("show", this);
33738 focus : function(){
33740 this.doFocus.defer(50, this);
33744 doFocus : function(){
33746 this.focusEl.focus();
33751 * Hides this menu and optionally all parent menus
33752 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
33754 hide : function(deep){
33755 if(this.el && this.isVisible()){
33756 this.fireEvent("beforehide", this);
33757 if(this.activeItem){
33758 this.activeItem.deactivate();
33759 this.activeItem = null;
33762 this.hidden = true;
33763 this.fireEvent("hide", this);
33765 if(deep === true && this.parentMenu){
33766 this.parentMenu.hide(true);
33771 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
33772 * Any of the following are valid:
33774 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
33775 * <li>An HTMLElement object which will be converted to a menu item</li>
33776 * <li>A menu item config object that will be created as a new menu item</li>
33777 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
33778 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
33783 var menu = new Roo.menu.Menu();
33785 // Create a menu item to add by reference
33786 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
33788 // Add a bunch of items at once using different methods.
33789 // Only the last item added will be returned.
33790 var item = menu.add(
33791 menuItem, // add existing item by ref
33792 'Dynamic Item', // new TextItem
33793 '-', // new separator
33794 { text: 'Config Item' } // new item by config
33797 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
33798 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
33801 var a = arguments, l = a.length, item;
33802 for(var i = 0; i < l; i++){
33804 if(el.render){ // some kind of Item
33805 item = this.addItem(el);
33806 }else if(typeof el == "string"){ // string
33807 if(el == "separator" || el == "-"){
33808 item = this.addSeparator();
33810 item = this.addText(el);
33812 }else if(el.tagName || el.el){ // element
33813 item = this.addElement(el);
33814 }else if(typeof el == "object"){ // must be menu item config?
33815 item = this.addMenuItem(el);
33822 * Returns this menu's underlying {@link Roo.Element} object
33823 * @return {Roo.Element} The element
33825 getEl : function(){
33833 * Adds a separator bar to the menu
33834 * @return {Roo.menu.Item} The menu item that was added
33836 addSeparator : function(){
33837 return this.addItem(new Roo.menu.Separator());
33841 * Adds an {@link Roo.Element} object to the menu
33842 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
33843 * @return {Roo.menu.Item} The menu item that was added
33845 addElement : function(el){
33846 return this.addItem(new Roo.menu.BaseItem(el));
33850 * Adds an existing object based on {@link Roo.menu.Item} to the menu
33851 * @param {Roo.menu.Item} item The menu item to add
33852 * @return {Roo.menu.Item} The menu item that was added
33854 addItem : function(item){
33855 this.items.add(item);
33857 var li = document.createElement("li");
33858 li.className = "x-menu-list-item";
33859 this.ul.dom.appendChild(li);
33860 item.render(li, this);
33861 this.delayAutoWidth();
33867 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
33868 * @param {Object} config A MenuItem config object
33869 * @return {Roo.menu.Item} The menu item that was added
33871 addMenuItem : function(config){
33872 if(!(config instanceof Roo.menu.Item)){
33873 if(typeof config.checked == "boolean"){ // must be check menu item config?
33874 config = new Roo.menu.CheckItem(config);
33876 config = new Roo.menu.Item(config);
33879 return this.addItem(config);
33883 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
33884 * @param {String} text The text to display in the menu item
33885 * @return {Roo.menu.Item} The menu item that was added
33887 addText : function(text){
33888 return this.addItem(new Roo.menu.TextItem(text));
33892 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
33893 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
33894 * @param {Roo.menu.Item} item The menu item to add
33895 * @return {Roo.menu.Item} The menu item that was added
33897 insert : function(index, item){
33898 this.items.insert(index, item);
33900 var li = document.createElement("li");
33901 li.className = "x-menu-list-item";
33902 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
33903 item.render(li, this);
33904 this.delayAutoWidth();
33910 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
33911 * @param {Roo.menu.Item} item The menu item to remove
33913 remove : function(item){
33914 this.items.removeKey(item.id);
33919 * Removes and destroys all items in the menu
33921 removeAll : function(){
33923 while(f = this.items.first()){
33929 // MenuNav is a private utility class used internally by the Menu
33930 Roo.menu.MenuNav = function(menu){
33931 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
33932 this.scope = this.menu = menu;
33935 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
33936 doRelay : function(e, h){
33937 var k = e.getKey();
33938 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
33939 this.menu.tryActivate(0, 1);
33942 return h.call(this.scope || this, e, this.menu);
33945 up : function(e, m){
33946 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
33947 m.tryActivate(m.items.length-1, -1);
33951 down : function(e, m){
33952 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
33953 m.tryActivate(0, 1);
33957 right : function(e, m){
33959 m.activeItem.expandMenu(true);
33963 left : function(e, m){
33965 if(m.parentMenu && m.parentMenu.activeItem){
33966 m.parentMenu.activeItem.activate();
33970 enter : function(e, m){
33972 e.stopPropagation();
33973 m.activeItem.onClick(e);
33974 m.fireEvent("click", this, m.activeItem);
33980 * Ext JS Library 1.1.1
33981 * Copyright(c) 2006-2007, Ext JS, LLC.
33983 * Originally Released Under LGPL - original licence link has changed is not relivant.
33986 * <script type="text/javascript">
33990 * @class Roo.menu.MenuMgr
33991 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
33994 Roo.menu.MenuMgr = function(){
33995 var menus, active, groups = {}, attached = false, lastShow = new Date();
33997 // private - called when first menu is created
34000 active = new Roo.util.MixedCollection();
34001 Roo.get(document).addKeyListener(27, function(){
34002 if(active.length > 0){
34009 function hideAll(){
34010 if(active && active.length > 0){
34011 var c = active.clone();
34012 c.each(function(m){
34019 function onHide(m){
34021 if(active.length < 1){
34022 Roo.get(document).un("mousedown", onMouseDown);
34028 function onShow(m){
34029 var last = active.last();
34030 lastShow = new Date();
34033 Roo.get(document).on("mousedown", onMouseDown);
34037 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34038 m.parentMenu.activeChild = m;
34039 }else if(last && last.isVisible()){
34040 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34045 function onBeforeHide(m){
34047 m.activeChild.hide();
34049 if(m.autoHideTimer){
34050 clearTimeout(m.autoHideTimer);
34051 delete m.autoHideTimer;
34056 function onBeforeShow(m){
34057 var pm = m.parentMenu;
34058 if(!pm && !m.allowOtherMenus){
34060 }else if(pm && pm.activeChild && active != m){
34061 pm.activeChild.hide();
34066 function onMouseDown(e){
34067 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34073 function onBeforeCheck(mi, state){
34075 var g = groups[mi.group];
34076 for(var i = 0, l = g.length; i < l; i++){
34078 g[i].setChecked(false);
34087 * Hides all menus that are currently visible
34089 hideAll : function(){
34094 register : function(menu){
34098 menus[menu.id] = menu;
34099 menu.on("beforehide", onBeforeHide);
34100 menu.on("hide", onHide);
34101 menu.on("beforeshow", onBeforeShow);
34102 menu.on("show", onShow);
34103 var g = menu.group;
34104 if(g && menu.events["checkchange"]){
34108 groups[g].push(menu);
34109 menu.on("checkchange", onCheck);
34114 * Returns a {@link Roo.menu.Menu} object
34115 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34116 * be used to generate and return a new Menu instance.
34118 get : function(menu){
34119 if(typeof menu == "string"){ // menu id
34120 return menus[menu];
34121 }else if(menu.events){ // menu instance
34123 }else if(typeof menu.length == 'number'){ // array of menu items?
34124 return new Roo.menu.Menu({items:menu});
34125 }else{ // otherwise, must be a config
34126 return new Roo.menu.Menu(menu);
34131 unregister : function(menu){
34132 delete menus[menu.id];
34133 menu.un("beforehide", onBeforeHide);
34134 menu.un("hide", onHide);
34135 menu.un("beforeshow", onBeforeShow);
34136 menu.un("show", onShow);
34137 var g = menu.group;
34138 if(g && menu.events["checkchange"]){
34139 groups[g].remove(menu);
34140 menu.un("checkchange", onCheck);
34145 registerCheckable : function(menuItem){
34146 var g = menuItem.group;
34151 groups[g].push(menuItem);
34152 menuItem.on("beforecheckchange", onBeforeCheck);
34157 unregisterCheckable : function(menuItem){
34158 var g = menuItem.group;
34160 groups[g].remove(menuItem);
34161 menuItem.un("beforecheckchange", onBeforeCheck);
34167 * Ext JS Library 1.1.1
34168 * Copyright(c) 2006-2007, Ext JS, LLC.
34170 * Originally Released Under LGPL - original licence link has changed is not relivant.
34173 * <script type="text/javascript">
34178 * @class Roo.menu.BaseItem
34179 * @extends Roo.Component
34180 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34181 * management and base configuration options shared by all menu components.
34183 * Creates a new BaseItem
34184 * @param {Object} config Configuration options
34186 Roo.menu.BaseItem = function(config){
34187 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34192 * Fires when this item is clicked
34193 * @param {Roo.menu.BaseItem} this
34194 * @param {Roo.EventObject} e
34199 * Fires when this item is activated
34200 * @param {Roo.menu.BaseItem} this
34204 * @event deactivate
34205 * Fires when this item is deactivated
34206 * @param {Roo.menu.BaseItem} this
34212 this.on("click", this.handler, this.scope, true);
34216 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34218 * @cfg {Function} handler
34219 * A function that will handle the click event of this menu item (defaults to undefined)
34222 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34224 canActivate : false,
34226 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34228 activeClass : "x-menu-item-active",
34230 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34232 hideOnClick : true,
34234 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34239 ctype: "Roo.menu.BaseItem",
34242 actionMode : "container",
34245 render : function(container, parentMenu){
34246 this.parentMenu = parentMenu;
34247 Roo.menu.BaseItem.superclass.render.call(this, container);
34248 this.container.menuItemId = this.id;
34252 onRender : function(container, position){
34253 this.el = Roo.get(this.el);
34254 container.dom.appendChild(this.el.dom);
34258 onClick : function(e){
34259 if(!this.disabled && this.fireEvent("click", this, e) !== false
34260 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34261 this.handleClick(e);
34268 activate : function(){
34272 var li = this.container;
34273 li.addClass(this.activeClass);
34274 this.region = li.getRegion().adjust(2, 2, -2, -2);
34275 this.fireEvent("activate", this);
34280 deactivate : function(){
34281 this.container.removeClass(this.activeClass);
34282 this.fireEvent("deactivate", this);
34286 shouldDeactivate : function(e){
34287 return !this.region || !this.region.contains(e.getPoint());
34291 handleClick : function(e){
34292 if(this.hideOnClick){
34293 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34298 expandMenu : function(autoActivate){
34303 hideMenu : function(){
34308 * Ext JS Library 1.1.1
34309 * Copyright(c) 2006-2007, Ext JS, LLC.
34311 * Originally Released Under LGPL - original licence link has changed is not relivant.
34314 * <script type="text/javascript">
34318 * @class Roo.menu.Adapter
34319 * @extends Roo.menu.BaseItem
34320 * 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.
34321 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34323 * Creates a new Adapter
34324 * @param {Object} config Configuration options
34326 Roo.menu.Adapter = function(component, config){
34327 Roo.menu.Adapter.superclass.constructor.call(this, config);
34328 this.component = component;
34330 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34332 canActivate : true,
34335 onRender : function(container, position){
34336 this.component.render(container);
34337 this.el = this.component.getEl();
34341 activate : function(){
34345 this.component.focus();
34346 this.fireEvent("activate", this);
34351 deactivate : function(){
34352 this.fireEvent("deactivate", this);
34356 disable : function(){
34357 this.component.disable();
34358 Roo.menu.Adapter.superclass.disable.call(this);
34362 enable : function(){
34363 this.component.enable();
34364 Roo.menu.Adapter.superclass.enable.call(this);
34368 * Ext JS Library 1.1.1
34369 * Copyright(c) 2006-2007, Ext JS, LLC.
34371 * Originally Released Under LGPL - original licence link has changed is not relivant.
34374 * <script type="text/javascript">
34378 * @class Roo.menu.TextItem
34379 * @extends Roo.menu.BaseItem
34380 * Adds a static text string to a menu, usually used as either a heading or group separator.
34382 * Creates a new TextItem
34383 * @param {String} text The text to display
34385 Roo.menu.TextItem = function(text){
34387 Roo.menu.TextItem.superclass.constructor.call(this);
34390 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34392 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34394 hideOnClick : false,
34396 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34398 itemCls : "x-menu-text",
34401 onRender : function(){
34402 var s = document.createElement("span");
34403 s.className = this.itemCls;
34404 s.innerHTML = this.text;
34406 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34410 * Ext JS Library 1.1.1
34411 * Copyright(c) 2006-2007, Ext JS, LLC.
34413 * Originally Released Under LGPL - original licence link has changed is not relivant.
34416 * <script type="text/javascript">
34420 * @class Roo.menu.Separator
34421 * @extends Roo.menu.BaseItem
34422 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34423 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34425 * @param {Object} config Configuration options
34427 Roo.menu.Separator = function(config){
34428 Roo.menu.Separator.superclass.constructor.call(this, config);
34431 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34433 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34435 itemCls : "x-menu-sep",
34437 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34439 hideOnClick : false,
34442 onRender : function(li){
34443 var s = document.createElement("span");
34444 s.className = this.itemCls;
34445 s.innerHTML = " ";
34447 li.addClass("x-menu-sep-li");
34448 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34452 * Ext JS Library 1.1.1
34453 * Copyright(c) 2006-2007, Ext JS, LLC.
34455 * Originally Released Under LGPL - original licence link has changed is not relivant.
34458 * <script type="text/javascript">
34461 * @class Roo.menu.Item
34462 * @extends Roo.menu.BaseItem
34463 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34464 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34465 * activation and click handling.
34467 * Creates a new Item
34468 * @param {Object} config Configuration options
34470 Roo.menu.Item = function(config){
34471 Roo.menu.Item.superclass.constructor.call(this, config);
34473 this.menu = Roo.menu.MenuMgr.get(this.menu);
34476 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34478 * @cfg {String} icon
34479 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34482 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34484 itemCls : "x-menu-item",
34486 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34488 canActivate : true,
34490 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34493 // doc'd in BaseItem
34497 ctype: "Roo.menu.Item",
34500 onRender : function(container, position){
34501 var el = document.createElement("a");
34502 el.hideFocus = true;
34503 el.unselectable = "on";
34504 el.href = this.href || "#";
34505 if(this.hrefTarget){
34506 el.target = this.hrefTarget;
34508 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34509 el.innerHTML = String.format(
34510 '<img src="{0}" class="x-menu-item-icon {2}" />{1}',
34511 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || '');
34513 Roo.menu.Item.superclass.onRender.call(this, container, position);
34517 * Sets the text to display in this menu item
34518 * @param {String} text The text to display
34520 setText : function(text){
34523 this.el.update(String.format(
34524 '<img src="{0}" class="x-menu-item-icon {2}">{1}',
34525 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34526 this.parentMenu.autoWidth();
34531 handleClick : function(e){
34532 if(!this.href){ // if no link defined, stop the event automatically
34535 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34539 activate : function(autoExpand){
34540 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34550 shouldDeactivate : function(e){
34551 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34552 if(this.menu && this.menu.isVisible()){
34553 return !this.menu.getEl().getRegion().contains(e.getPoint());
34561 deactivate : function(){
34562 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34567 expandMenu : function(autoActivate){
34568 if(!this.disabled && this.menu){
34569 clearTimeout(this.hideTimer);
34570 delete this.hideTimer;
34571 if(!this.menu.isVisible() && !this.showTimer){
34572 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34573 }else if (this.menu.isVisible() && autoActivate){
34574 this.menu.tryActivate(0, 1);
34580 deferExpand : function(autoActivate){
34581 delete this.showTimer;
34582 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34584 this.menu.tryActivate(0, 1);
34589 hideMenu : function(){
34590 clearTimeout(this.showTimer);
34591 delete this.showTimer;
34592 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34593 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34598 deferHide : function(){
34599 delete this.hideTimer;
34604 * Ext JS Library 1.1.1
34605 * Copyright(c) 2006-2007, Ext JS, LLC.
34607 * Originally Released Under LGPL - original licence link has changed is not relivant.
34610 * <script type="text/javascript">
34614 * @class Roo.menu.CheckItem
34615 * @extends Roo.menu.Item
34616 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34618 * Creates a new CheckItem
34619 * @param {Object} config Configuration options
34621 Roo.menu.CheckItem = function(config){
34622 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34625 * @event beforecheckchange
34626 * Fires before the checked value is set, providing an opportunity to cancel if needed
34627 * @param {Roo.menu.CheckItem} this
34628 * @param {Boolean} checked The new checked value that will be set
34630 "beforecheckchange" : true,
34632 * @event checkchange
34633 * Fires after the checked value has been set
34634 * @param {Roo.menu.CheckItem} this
34635 * @param {Boolean} checked The checked value that was set
34637 "checkchange" : true
34639 if(this.checkHandler){
34640 this.on('checkchange', this.checkHandler, this.scope);
34643 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34645 * @cfg {String} group
34646 * All check items with the same group name will automatically be grouped into a single-select
34647 * radio button group (defaults to '')
34650 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34652 itemCls : "x-menu-item x-menu-check-item",
34654 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34656 groupClass : "x-menu-group-item",
34659 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34660 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34661 * initialized with checked = true will be rendered as checked.
34666 ctype: "Roo.menu.CheckItem",
34669 onRender : function(c){
34670 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34672 this.el.addClass(this.groupClass);
34674 Roo.menu.MenuMgr.registerCheckable(this);
34676 this.checked = false;
34677 this.setChecked(true, true);
34682 destroy : function(){
34684 Roo.menu.MenuMgr.unregisterCheckable(this);
34686 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34690 * Set the checked state of this item
34691 * @param {Boolean} checked The new checked value
34692 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
34694 setChecked : function(state, suppressEvent){
34695 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
34696 if(this.container){
34697 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
34699 this.checked = state;
34700 if(suppressEvent !== true){
34701 this.fireEvent("checkchange", this, state);
34707 handleClick : function(e){
34708 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
34709 this.setChecked(!this.checked);
34711 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
34715 * Ext JS Library 1.1.1
34716 * Copyright(c) 2006-2007, Ext JS, LLC.
34718 * Originally Released Under LGPL - original licence link has changed is not relivant.
34721 * <script type="text/javascript">
34725 * @class Roo.menu.DateItem
34726 * @extends Roo.menu.Adapter
34727 * A menu item that wraps the {@link Roo.DatPicker} component.
34729 * Creates a new DateItem
34730 * @param {Object} config Configuration options
34732 Roo.menu.DateItem = function(config){
34733 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
34734 /** The Roo.DatePicker object @type Roo.DatePicker */
34735 this.picker = this.component;
34736 this.addEvents({select: true});
34738 this.picker.on("render", function(picker){
34739 picker.getEl().swallowEvent("click");
34740 picker.container.addClass("x-menu-date-item");
34743 this.picker.on("select", this.onSelect, this);
34746 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
34748 onSelect : function(picker, date){
34749 this.fireEvent("select", this, date, picker);
34750 Roo.menu.DateItem.superclass.handleClick.call(this);
34754 * Ext JS Library 1.1.1
34755 * Copyright(c) 2006-2007, Ext JS, LLC.
34757 * Originally Released Under LGPL - original licence link has changed is not relivant.
34760 * <script type="text/javascript">
34764 * @class Roo.menu.ColorItem
34765 * @extends Roo.menu.Adapter
34766 * A menu item that wraps the {@link Roo.ColorPalette} component.
34768 * Creates a new ColorItem
34769 * @param {Object} config Configuration options
34771 Roo.menu.ColorItem = function(config){
34772 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
34773 /** The Roo.ColorPalette object @type Roo.ColorPalette */
34774 this.palette = this.component;
34775 this.relayEvents(this.palette, ["select"]);
34776 if(this.selectHandler){
34777 this.on('select', this.selectHandler, this.scope);
34780 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
34782 * Ext JS Library 1.1.1
34783 * Copyright(c) 2006-2007, Ext JS, LLC.
34785 * Originally Released Under LGPL - original licence link has changed is not relivant.
34788 * <script type="text/javascript">
34793 * @class Roo.menu.DateMenu
34794 * @extends Roo.menu.Menu
34795 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
34797 * Creates a new DateMenu
34798 * @param {Object} config Configuration options
34800 Roo.menu.DateMenu = function(config){
34801 Roo.menu.DateMenu.superclass.constructor.call(this, config);
34803 var di = new Roo.menu.DateItem(config);
34806 * The {@link Roo.DatePicker} instance for this DateMenu
34809 this.picker = di.picker;
34812 * @param {DatePicker} picker
34813 * @param {Date} date
34815 this.relayEvents(di, ["select"]);
34817 this.on('beforeshow', function(){
34819 this.picker.hideMonthPicker(true);
34823 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
34827 * Ext JS Library 1.1.1
34828 * Copyright(c) 2006-2007, Ext JS, LLC.
34830 * Originally Released Under LGPL - original licence link has changed is not relivant.
34833 * <script type="text/javascript">
34838 * @class Roo.menu.ColorMenu
34839 * @extends Roo.menu.Menu
34840 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
34842 * Creates a new ColorMenu
34843 * @param {Object} config Configuration options
34845 Roo.menu.ColorMenu = function(config){
34846 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
34848 var ci = new Roo.menu.ColorItem(config);
34851 * The {@link Roo.ColorPalette} instance for this ColorMenu
34852 * @type ColorPalette
34854 this.palette = ci.palette;
34857 * @param {ColorPalette} palette
34858 * @param {String} color
34860 this.relayEvents(ci, ["select"]);
34862 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
34864 * Ext JS Library 1.1.1
34865 * Copyright(c) 2006-2007, Ext JS, LLC.
34867 * Originally Released Under LGPL - original licence link has changed is not relivant.
34870 * <script type="text/javascript">
34874 * @class Roo.form.Field
34875 * @extends Roo.BoxComponent
34876 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
34878 * Creates a new Field
34879 * @param {Object} config Configuration options
34881 Roo.form.Field = function(config){
34882 Roo.form.Field.superclass.constructor.call(this, config);
34885 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
34887 * @cfg {String} fieldLabel Label to use when rendering a form.
34890 * @cfg {String} qtip Mouse over tip
34894 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
34896 invalidClass : "x-form-invalid",
34898 * @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")
34900 invalidText : "The value in this field is invalid",
34902 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
34904 focusClass : "x-form-focus",
34906 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
34907 automatic validation (defaults to "keyup").
34909 validationEvent : "keyup",
34911 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
34913 validateOnBlur : true,
34915 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
34917 validationDelay : 250,
34919 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
34920 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
34922 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
34924 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
34926 fieldClass : "x-form-field",
34928 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
34931 ----------- ----------------------------------------------------------------------
34932 qtip Display a quick tip when the user hovers over the field
34933 title Display a default browser title attribute popup
34934 under Add a block div beneath the field containing the error text
34935 side Add an error icon to the right of the field with a popup on hover
34936 [element id] Add the error text directly to the innerHTML of the specified element
34939 msgTarget : 'qtip',
34941 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
34946 * @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.
34951 * @cfg {Boolean} disabled True to disable the field (defaults to false).
34956 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
34958 inputType : undefined,
34961 * @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).
34963 tabIndex : undefined,
34966 isFormField : true,
34971 * @property {Roo.Element} fieldEl
34972 * Element Containing the rendered Field (with label etc.)
34975 * @cfg {Mixed} value A value to initialize this field with.
34980 * @cfg {String} name The field's HTML name attribute.
34983 * @cfg {String} cls A CSS class to apply to the field's underlying element.
34987 initComponent : function(){
34988 Roo.form.Field.superclass.initComponent.call(this);
34992 * Fires when this field receives input focus.
34993 * @param {Roo.form.Field} this
34998 * Fires when this field loses input focus.
34999 * @param {Roo.form.Field} this
35003 * @event specialkey
35004 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35005 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35006 * @param {Roo.form.Field} this
35007 * @param {Roo.EventObject} e The event object
35012 * Fires just before the field blurs if the field value has changed.
35013 * @param {Roo.form.Field} this
35014 * @param {Mixed} newValue The new value
35015 * @param {Mixed} oldValue The original value
35020 * Fires after the field has been marked as invalid.
35021 * @param {Roo.form.Field} this
35022 * @param {String} msg The validation message
35027 * Fires after the field has been validated with no errors.
35028 * @param {Roo.form.Field} this
35035 * Returns the name attribute of the field if available
35036 * @return {String} name The field name
35038 getName: function(){
35039 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35043 onRender : function(ct, position){
35044 Roo.form.Field.superclass.onRender.call(this, ct, position);
35046 var cfg = this.getAutoCreate();
35048 cfg.name = this.name || this.id;
35050 if(this.inputType){
35051 cfg.type = this.inputType;
35053 this.el = ct.createChild(cfg, position);
35055 var type = this.el.dom.type;
35057 if(type == 'password'){
35060 this.el.addClass('x-form-'+type);
35063 this.el.dom.readOnly = true;
35065 if(this.tabIndex !== undefined){
35066 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35069 this.el.addClass([this.fieldClass, this.cls]);
35074 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35075 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35076 * @return {Roo.form.Field} this
35078 applyTo : function(target){
35079 this.allowDomMove = false;
35080 this.el = Roo.get(target);
35081 this.render(this.el.dom.parentNode);
35086 initValue : function(){
35087 if(this.value !== undefined){
35088 this.setValue(this.value);
35089 }else if(this.el.dom.value.length > 0){
35090 this.setValue(this.el.dom.value);
35095 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35097 isDirty : function() {
35098 if(this.disabled) {
35101 return String(this.getValue()) !== String(this.originalValue);
35105 afterRender : function(){
35106 Roo.form.Field.superclass.afterRender.call(this);
35111 fireKey : function(e){
35112 if(e.isNavKeyPress()){
35113 this.fireEvent("specialkey", this, e);
35118 * Resets the current field value to the originally loaded value and clears any validation messages
35120 reset : function(){
35121 this.setValue(this.originalValue);
35122 this.clearInvalid();
35126 initEvents : function(){
35127 this.el.on(Roo.isIE ? "keydown" : "keypress", this.fireKey, this);
35128 this.el.on("focus", this.onFocus, this);
35129 this.el.on("blur", this.onBlur, this);
35131 // reference to original value for reset
35132 this.originalValue = this.getValue();
35136 onFocus : function(){
35137 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35138 this.el.addClass(this.focusClass);
35140 if(!this.hasFocus){
35141 this.hasFocus = true;
35142 this.startValue = this.getValue();
35143 this.fireEvent("focus", this);
35147 beforeBlur : Roo.emptyFn,
35150 onBlur : function(){
35152 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35153 this.el.removeClass(this.focusClass);
35155 this.hasFocus = false;
35156 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35159 var v = this.getValue();
35160 if(String(v) !== String(this.startValue)){
35161 this.fireEvent('change', this, v, this.startValue);
35163 this.fireEvent("blur", this);
35167 * Returns whether or not the field value is currently valid
35168 * @param {Boolean} preventMark True to disable marking the field invalid
35169 * @return {Boolean} True if the value is valid, else false
35171 isValid : function(preventMark){
35175 var restore = this.preventMark;
35176 this.preventMark = preventMark === true;
35177 var v = this.validateValue(this.processValue(this.getRawValue()));
35178 this.preventMark = restore;
35183 * Validates the field value
35184 * @return {Boolean} True if the value is valid, else false
35186 validate : function(){
35187 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35188 this.clearInvalid();
35194 processValue : function(value){
35199 // Subclasses should provide the validation implementation by overriding this
35200 validateValue : function(value){
35205 * Mark this field as invalid
35206 * @param {String} msg The validation message
35208 markInvalid : function(msg){
35209 if(!this.rendered || this.preventMark){ // not rendered
35212 this.el.addClass(this.invalidClass);
35213 msg = msg || this.invalidText;
35214 switch(this.msgTarget){
35216 this.el.dom.qtip = msg;
35217 this.el.dom.qclass = 'x-form-invalid-tip';
35218 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35219 Roo.QuickTips.enable();
35223 this.el.dom.title = msg;
35227 var elp = this.el.findParent('.x-form-element', 5, true);
35228 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35229 this.errorEl.setWidth(elp.getWidth(true)-20);
35231 this.errorEl.update(msg);
35232 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35235 if(!this.errorIcon){
35236 var elp = this.el.findParent('.x-form-element', 5, true);
35237 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35239 this.alignErrorIcon();
35240 this.errorIcon.dom.qtip = msg;
35241 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35242 this.errorIcon.show();
35243 this.on('resize', this.alignErrorIcon, this);
35246 var t = Roo.getDom(this.msgTarget);
35248 t.style.display = this.msgDisplay;
35251 this.fireEvent('invalid', this, msg);
35255 alignErrorIcon : function(){
35256 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35260 * Clear any invalid styles/messages for this field
35262 clearInvalid : function(){
35263 if(!this.rendered || this.preventMark){ // not rendered
35266 this.el.removeClass(this.invalidClass);
35267 switch(this.msgTarget){
35269 this.el.dom.qtip = '';
35272 this.el.dom.title = '';
35276 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35280 if(this.errorIcon){
35281 this.errorIcon.dom.qtip = '';
35282 this.errorIcon.hide();
35283 this.un('resize', this.alignErrorIcon, this);
35287 var t = Roo.getDom(this.msgTarget);
35289 t.style.display = 'none';
35292 this.fireEvent('valid', this);
35296 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35297 * @return {Mixed} value The field value
35299 getRawValue : function(){
35300 var v = this.el.getValue();
35301 if(v === this.emptyText){
35308 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35309 * @return {Mixed} value The field value
35311 getValue : function(){
35312 var v = this.el.getValue();
35313 if(v === this.emptyText || v === undefined){
35320 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35321 * @param {Mixed} value The value to set
35323 setRawValue : function(v){
35324 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35328 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35329 * @param {Mixed} value The value to set
35331 setValue : function(v){
35334 this.el.dom.value = (v === null || v === undefined ? '' : v);
35339 adjustSize : function(w, h){
35340 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35341 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35345 adjustWidth : function(tag, w){
35346 tag = tag.toLowerCase();
35347 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35348 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35349 if(tag == 'input'){
35352 if(tag = 'textarea'){
35355 }else if(Roo.isOpera){
35356 if(tag == 'input'){
35359 if(tag = 'textarea'){
35369 // anything other than normal should be considered experimental
35370 Roo.form.Field.msgFx = {
35372 show: function(msgEl, f){
35373 msgEl.setDisplayed('block');
35376 hide : function(msgEl, f){
35377 msgEl.setDisplayed(false).update('');
35382 show: function(msgEl, f){
35383 msgEl.slideIn('t', {stopFx:true});
35386 hide : function(msgEl, f){
35387 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35392 show: function(msgEl, f){
35393 msgEl.fixDisplay();
35394 msgEl.alignTo(f.el, 'tl-tr');
35395 msgEl.slideIn('l', {stopFx:true});
35398 hide : function(msgEl, f){
35399 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35404 * Ext JS Library 1.1.1
35405 * Copyright(c) 2006-2007, Ext JS, LLC.
35407 * Originally Released Under LGPL - original licence link has changed is not relivant.
35410 * <script type="text/javascript">
35415 * @class Roo.form.TextField
35416 * @extends Roo.form.Field
35417 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35418 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35420 * Creates a new TextField
35421 * @param {Object} config Configuration options
35423 Roo.form.TextField = function(config){
35424 Roo.form.TextField.superclass.constructor.call(this, config);
35428 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35429 * according to the default logic, but this event provides a hook for the developer to apply additional
35430 * logic at runtime to resize the field if needed.
35431 * @param {Roo.form.Field} this This text field
35432 * @param {Number} width The new field width
35438 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35440 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35444 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35448 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35452 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35456 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35460 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35462 disableKeyFilter : false,
35464 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35468 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35472 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35474 maxLength : Number.MAX_VALUE,
35476 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35478 minLengthText : "The minimum length for this field is {0}",
35480 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35482 maxLengthText : "The maximum length for this field is {0}",
35484 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35486 selectOnFocus : false,
35488 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35490 blankText : "This field is required",
35492 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35493 * If available, this function will be called only after the basic validators all return true, and will be passed the
35494 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35498 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35499 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35500 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35504 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35508 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35512 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35513 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35515 emptyClass : 'x-form-empty-field',
35518 initEvents : function(){
35519 Roo.form.TextField.superclass.initEvents.call(this);
35520 if(this.validationEvent == 'keyup'){
35521 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35522 this.el.on('keyup', this.filterValidation, this);
35524 else if(this.validationEvent !== false){
35525 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35527 if(this.selectOnFocus || this.emptyText){
35528 this.on("focus", this.preFocus, this);
35529 if(this.emptyText){
35530 this.on('blur', this.postBlur, this);
35531 this.applyEmptyText();
35534 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35535 this.el.on("keypress", this.filterKeys, this);
35538 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35539 this.el.on("click", this.autoSize, this);
35543 processValue : function(value){
35544 if(this.stripCharsRe){
35545 var newValue = value.replace(this.stripCharsRe, '');
35546 if(newValue !== value){
35547 this.setRawValue(newValue);
35554 filterValidation : function(e){
35555 if(!e.isNavKeyPress()){
35556 this.validationTask.delay(this.validationDelay);
35561 onKeyUp : function(e){
35562 if(!e.isNavKeyPress()){
35568 * Resets the current field value to the originally-loaded value and clears any validation messages.
35569 * Also adds emptyText and emptyClass if the original value was blank.
35571 reset : function(){
35572 Roo.form.TextField.superclass.reset.call(this);
35573 this.applyEmptyText();
35576 applyEmptyText : function(){
35577 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35578 this.setRawValue(this.emptyText);
35579 this.el.addClass(this.emptyClass);
35584 preFocus : function(){
35585 if(this.emptyText){
35586 if(this.el.dom.value == this.emptyText){
35587 this.setRawValue('');
35589 this.el.removeClass(this.emptyClass);
35591 if(this.selectOnFocus){
35592 this.el.dom.select();
35597 postBlur : function(){
35598 this.applyEmptyText();
35602 filterKeys : function(e){
35603 var k = e.getKey();
35604 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35607 var c = e.getCharCode(), cc = String.fromCharCode(c);
35608 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35611 if(!this.maskRe.test(cc)){
35616 setValue : function(v){
35617 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35618 this.el.removeClass(this.emptyClass);
35620 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35621 this.applyEmptyText();
35626 * Validates a value according to the field's validation rules and marks the field as invalid
35627 * if the validation fails
35628 * @param {Mixed} value The value to validate
35629 * @return {Boolean} True if the value is valid, else false
35631 validateValue : function(value){
35632 if(value.length < 1 || value === this.emptyText){ // if it's blank
35633 if(this.allowBlank){
35634 this.clearInvalid();
35637 this.markInvalid(this.blankText);
35641 if(value.length < this.minLength){
35642 this.markInvalid(String.format(this.minLengthText, this.minLength));
35645 if(value.length > this.maxLength){
35646 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35650 var vt = Roo.form.VTypes;
35651 if(!vt[this.vtype](value, this)){
35652 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35656 if(typeof this.validator == "function"){
35657 var msg = this.validator(value);
35659 this.markInvalid(msg);
35663 if(this.regex && !this.regex.test(value)){
35664 this.markInvalid(this.regexText);
35671 * Selects text in this field
35672 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35673 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35675 selectText : function(start, end){
35676 var v = this.getRawValue();
35678 start = start === undefined ? 0 : start;
35679 end = end === undefined ? v.length : end;
35680 var d = this.el.dom;
35681 if(d.setSelectionRange){
35682 d.setSelectionRange(start, end);
35683 }else if(d.createTextRange){
35684 var range = d.createTextRange();
35685 range.moveStart("character", start);
35686 range.moveEnd("character", v.length-end);
35693 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
35694 * This only takes effect if grow = true, and fires the autosize event.
35696 autoSize : function(){
35697 if(!this.grow || !this.rendered){
35701 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
35704 var v = el.dom.value;
35705 var d = document.createElement('div');
35706 d.appendChild(document.createTextNode(v));
35710 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
35711 this.el.setWidth(w);
35712 this.fireEvent("autosize", this, w);
35716 * Ext JS Library 1.1.1
35717 * Copyright(c) 2006-2007, Ext JS, LLC.
35719 * Originally Released Under LGPL - original licence link has changed is not relivant.
35722 * <script type="text/javascript">
35726 * @class Roo.form.Hidden
35727 * @extends Roo.form.TextField
35728 * Simple Hidden element used on forms
35730 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
35733 * Creates a new Hidden form element.
35734 * @param {Object} config Configuration options
35739 // easy hidden field...
35740 Roo.form.Hidden = function(config){
35741 Roo.form.Hidden.superclass.constructor.call(this, config);
35744 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
35746 inputType: 'hidden',
35749 labelSeparator: '',
35751 itemCls : 'x-form-item-display-none'
35759 * Ext JS Library 1.1.1
35760 * Copyright(c) 2006-2007, Ext JS, LLC.
35762 * Originally Released Under LGPL - original licence link has changed is not relivant.
35765 * <script type="text/javascript">
35769 * @class Roo.form.TriggerField
35770 * @extends Roo.form.TextField
35771 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
35772 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
35773 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
35774 * for which you can provide a custom implementation. For example:
35776 var trigger = new Roo.form.TriggerField();
35777 trigger.onTriggerClick = myTriggerFn;
35778 trigger.applyTo('my-field');
35781 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
35782 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
35783 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
35784 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
35786 * Create a new TriggerField.
35787 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
35788 * to the base TextField)
35790 Roo.form.TriggerField = function(config){
35791 this.mimicing = false;
35792 Roo.form.TriggerField.superclass.constructor.call(this, config);
35795 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
35797 * @cfg {String} triggerClass A CSS class to apply to the trigger
35800 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35801 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
35803 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
35805 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
35809 /** @cfg {Boolean} grow @hide */
35810 /** @cfg {Number} growMin @hide */
35811 /** @cfg {Number} growMax @hide */
35817 autoSize: Roo.emptyFn,
35821 deferHeight : true,
35824 actionMode : 'wrap',
35826 onResize : function(w, h){
35827 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
35828 if(typeof w == 'number'){
35829 this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));
35834 adjustSize : Roo.BoxComponent.prototype.adjustSize,
35837 getResizeEl : function(){
35842 getPositionEl : function(){
35847 alignErrorIcon : function(){
35848 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
35852 onRender : function(ct, position){
35853 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
35854 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
35855 this.trigger = this.wrap.createChild(this.triggerConfig ||
35856 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
35857 if(this.hideTrigger){
35858 this.trigger.setDisplayed(false);
35860 this.initTrigger();
35862 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
35867 initTrigger : function(){
35868 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
35869 this.trigger.addClassOnOver('x-form-trigger-over');
35870 this.trigger.addClassOnClick('x-form-trigger-click');
35874 onDestroy : function(){
35876 this.trigger.removeAllListeners();
35877 this.trigger.remove();
35880 this.wrap.remove();
35882 Roo.form.TriggerField.superclass.onDestroy.call(this);
35886 onFocus : function(){
35887 Roo.form.TriggerField.superclass.onFocus.call(this);
35888 if(!this.mimicing){
35889 this.wrap.addClass('x-trigger-wrap-focus');
35890 this.mimicing = true;
35891 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
35892 if(this.monitorTab){
35893 this.el.on("keydown", this.checkTab, this);
35899 checkTab : function(e){
35900 if(e.getKey() == e.TAB){
35901 this.triggerBlur();
35906 onBlur : function(){
35911 mimicBlur : function(e, t){
35912 if(!this.wrap.contains(t) && this.validateBlur()){
35913 this.triggerBlur();
35918 triggerBlur : function(){
35919 this.mimicing = false;
35920 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
35921 if(this.monitorTab){
35922 this.el.un("keydown", this.checkTab, this);
35924 this.wrap.removeClass('x-trigger-wrap-focus');
35925 Roo.form.TriggerField.superclass.onBlur.call(this);
35929 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
35930 validateBlur : function(e, t){
35935 onDisable : function(){
35936 Roo.form.TriggerField.superclass.onDisable.call(this);
35938 this.wrap.addClass('x-item-disabled');
35943 onEnable : function(){
35944 Roo.form.TriggerField.superclass.onEnable.call(this);
35946 this.wrap.removeClass('x-item-disabled');
35951 onShow : function(){
35952 var ae = this.getActionEl();
35955 ae.dom.style.display = '';
35956 ae.dom.style.visibility = 'visible';
35962 onHide : function(){
35963 var ae = this.getActionEl();
35964 ae.dom.style.display = 'none';
35968 * The function that should handle the trigger's click event. This method does nothing by default until overridden
35969 * by an implementing function.
35971 * @param {EventObject} e
35973 onTriggerClick : Roo.emptyFn
35976 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
35977 // to be extended by an implementing class. For an example of implementing this class, see the custom
35978 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
35979 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
35980 initComponent : function(){
35981 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
35983 this.triggerConfig = {
35984 tag:'span', cls:'x-form-twin-triggers', cn:[
35985 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
35986 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
35990 getTrigger : function(index){
35991 return this.triggers[index];
35994 initTrigger : function(){
35995 var ts = this.trigger.select('.x-form-trigger', true);
35996 this.wrap.setStyle('overflow', 'hidden');
35997 var triggerField = this;
35998 ts.each(function(t, all, index){
35999 t.hide = function(){
36000 var w = triggerField.wrap.getWidth();
36001 this.dom.style.display = 'none';
36002 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36004 t.show = function(){
36005 var w = triggerField.wrap.getWidth();
36006 this.dom.style.display = '';
36007 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36009 var triggerIndex = 'Trigger'+(index+1);
36011 if(this['hide'+triggerIndex]){
36012 t.dom.style.display = 'none';
36014 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36015 t.addClassOnOver('x-form-trigger-over');
36016 t.addClassOnClick('x-form-trigger-click');
36018 this.triggers = ts.elements;
36021 onTrigger1Click : Roo.emptyFn,
36022 onTrigger2Click : Roo.emptyFn
36025 * Ext JS Library 1.1.1
36026 * Copyright(c) 2006-2007, Ext JS, LLC.
36028 * Originally Released Under LGPL - original licence link has changed is not relivant.
36031 * <script type="text/javascript">
36035 * @class Roo.form.TextArea
36036 * @extends Roo.form.TextField
36037 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36038 * support for auto-sizing.
36040 * Creates a new TextArea
36041 * @param {Object} config Configuration options
36043 Roo.form.TextArea = function(config){
36044 Roo.form.TextArea.superclass.constructor.call(this, config);
36045 // these are provided exchanges for backwards compat
36046 // minHeight/maxHeight were replaced by growMin/growMax to be
36047 // compatible with TextField growing config values
36048 if(this.minHeight !== undefined){
36049 this.growMin = this.minHeight;
36051 if(this.maxHeight !== undefined){
36052 this.growMax = this.maxHeight;
36056 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36058 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36062 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36066 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36067 * in the field (equivalent to setting overflow: hidden, defaults to false)
36069 preventScrollbars: false,
36071 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36072 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36076 onRender : function(ct, position){
36078 this.defaultAutoCreate = {
36080 style:"width:300px;height:60px;",
36081 autocomplete: "off"
36084 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36086 this.textSizeEl = Roo.DomHelper.append(document.body, {
36087 tag: "pre", cls: "x-form-grow-sizer"
36089 if(this.preventScrollbars){
36090 this.el.setStyle("overflow", "hidden");
36092 this.el.setHeight(this.growMin);
36096 onDestroy : function(){
36097 if(this.textSizeEl){
36098 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36100 Roo.form.TextArea.superclass.onDestroy.call(this);
36104 onKeyUp : function(e){
36105 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36111 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36112 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36114 autoSize : function(){
36115 if(!this.grow || !this.textSizeEl){
36119 var v = el.dom.value;
36120 var ts = this.textSizeEl;
36123 ts.appendChild(document.createTextNode(v));
36126 Roo.fly(ts).setWidth(this.el.getWidth());
36128 v = "  ";
36131 v = v.replace(/\n/g, '<p> </p>');
36133 v += " \n ";
36136 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36137 if(h != this.lastHeight){
36138 this.lastHeight = h;
36139 this.el.setHeight(h);
36140 this.fireEvent("autosize", this, h);
36145 * Ext JS Library 1.1.1
36146 * Copyright(c) 2006-2007, Ext JS, LLC.
36148 * Originally Released Under LGPL - original licence link has changed is not relivant.
36151 * <script type="text/javascript">
36156 * @class Roo.form.NumberField
36157 * @extends Roo.form.TextField
36158 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36160 * Creates a new NumberField
36161 * @param {Object} config Configuration options
36163 Roo.form.NumberField = function(config){
36164 Roo.form.NumberField.superclass.constructor.call(this, config);
36167 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36169 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36171 fieldClass: "x-form-field x-form-num-field",
36173 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36175 allowDecimals : true,
36177 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36179 decimalSeparator : ".",
36181 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36183 decimalPrecision : 2,
36185 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36187 allowNegative : true,
36189 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36191 minValue : Number.NEGATIVE_INFINITY,
36193 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36195 maxValue : Number.MAX_VALUE,
36197 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36199 minText : "The minimum value for this field is {0}",
36201 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36203 maxText : "The maximum value for this field is {0}",
36205 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36206 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36208 nanText : "{0} is not a valid number",
36211 initEvents : function(){
36212 Roo.form.NumberField.superclass.initEvents.call(this);
36213 var allowed = "0123456789";
36214 if(this.allowDecimals){
36215 allowed += this.decimalSeparator;
36217 if(this.allowNegative){
36220 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36221 var keyPress = function(e){
36222 var k = e.getKey();
36223 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36226 var c = e.getCharCode();
36227 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36231 this.el.on("keypress", keyPress, this);
36235 validateValue : function(value){
36236 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36239 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36242 var num = this.parseValue(value);
36244 this.markInvalid(String.format(this.nanText, value));
36247 if(num < this.minValue){
36248 this.markInvalid(String.format(this.minText, this.minValue));
36251 if(num > this.maxValue){
36252 this.markInvalid(String.format(this.maxText, this.maxValue));
36258 getValue : function(){
36259 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36263 parseValue : function(value){
36264 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36265 return isNaN(value) ? '' : value;
36269 fixPrecision : function(value){
36270 var nan = isNaN(value);
36271 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36272 return nan ? '' : value;
36274 return parseFloat(value).toFixed(this.decimalPrecision);
36277 setValue : function(v){
36278 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36282 decimalPrecisionFcn : function(v){
36283 return Math.floor(v);
36286 beforeBlur : function(){
36287 var v = this.parseValue(this.getRawValue());
36289 this.setValue(this.fixPrecision(v));
36294 * Ext JS Library 1.1.1
36295 * Copyright(c) 2006-2007, Ext JS, LLC.
36297 * Originally Released Under LGPL - original licence link has changed is not relivant.
36300 * <script type="text/javascript">
36304 * @class Roo.form.DateField
36305 * @extends Roo.form.TriggerField
36306 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36308 * Create a new DateField
36309 * @param {Object} config
36311 Roo.form.DateField = function(config){
36312 Roo.form.DateField.superclass.constructor.call(this, config);
36318 * Fires when a date is selected
36319 * @param {Roo.form.DateField} combo This combo box
36320 * @param {Date} date The date selected
36327 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36328 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36329 this.ddMatch = null;
36330 if(this.disabledDates){
36331 var dd = this.disabledDates;
36333 for(var i = 0; i < dd.length; i++){
36335 if(i != dd.length-1) re += "|";
36337 this.ddMatch = new RegExp(re + ")");
36341 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36343 * @cfg {String} format
36344 * The default date format string which can be overriden for localization support. The format must be
36345 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36349 * @cfg {String} altFormats
36350 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36351 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36353 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36355 * @cfg {Array} disabledDays
36356 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36358 disabledDays : null,
36360 * @cfg {String} disabledDaysText
36361 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36363 disabledDaysText : "Disabled",
36365 * @cfg {Array} disabledDates
36366 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36367 * expression so they are very powerful. Some examples:
36369 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36370 * <li>["03/08", "09/16"] would disable those days for every year</li>
36371 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36372 * <li>["03/../2006"] would disable every day in March 2006</li>
36373 * <li>["^03"] would disable every day in every March</li>
36375 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36376 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36378 disabledDates : null,
36380 * @cfg {String} disabledDatesText
36381 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36383 disabledDatesText : "Disabled",
36385 * @cfg {Date/String} minValue
36386 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36387 * valid format (defaults to null).
36391 * @cfg {Date/String} maxValue
36392 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36393 * valid format (defaults to null).
36397 * @cfg {String} minText
36398 * The error text to display when the date in the cell is before minValue (defaults to
36399 * 'The date in this field must be after {minValue}').
36401 minText : "The date in this field must be equal to or after {0}",
36403 * @cfg {String} maxText
36404 * The error text to display when the date in the cell is after maxValue (defaults to
36405 * 'The date in this field must be before {maxValue}').
36407 maxText : "The date in this field must be equal to or before {0}",
36409 * @cfg {String} invalidText
36410 * The error text to display when the date in the field is invalid (defaults to
36411 * '{value} is not a valid date - it must be in the format {format}').
36413 invalidText : "{0} is not a valid date - it must be in the format {1}",
36415 * @cfg {String} triggerClass
36416 * An additional CSS class used to style the trigger button. The trigger will always get the
36417 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36418 * which displays a calendar icon).
36420 triggerClass : 'x-form-date-trigger',
36424 * @cfg {bool} useIso
36425 * if enabled, then the date field will use a hidden field to store the
36426 * real value as iso formated date. default (false)
36430 * @cfg {String/Object} autoCreate
36431 * A DomHelper element spec, or true for a default element spec (defaults to
36432 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36435 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36438 hiddenField: false,
36440 onRender : function(ct, position)
36442 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36444 this.el.dom.removeAttribute('name');
36445 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36447 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36448 // prevent input submission
36449 this.hiddenName = this.name;
36456 validateValue : function(value)
36458 value = this.formatDate(value);
36459 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36462 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36465 var svalue = value;
36466 value = this.parseDate(value);
36468 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36471 var time = value.getTime();
36472 if(this.minValue && time < this.minValue.getTime()){
36473 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36476 if(this.maxValue && time > this.maxValue.getTime()){
36477 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36480 if(this.disabledDays){
36481 var day = value.getDay();
36482 for(var i = 0; i < this.disabledDays.length; i++) {
36483 if(day === this.disabledDays[i]){
36484 this.markInvalid(this.disabledDaysText);
36489 var fvalue = this.formatDate(value);
36490 if(this.ddMatch && this.ddMatch.test(fvalue)){
36491 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36498 // Provides logic to override the default TriggerField.validateBlur which just returns true
36499 validateBlur : function(){
36500 return !this.menu || !this.menu.isVisible();
36504 * Returns the current date value of the date field.
36505 * @return {Date} The date value
36507 getValue : function(){
36509 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36513 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36514 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36515 * (the default format used is "m/d/y").
36518 //All of these calls set the same date value (May 4, 2006)
36520 //Pass a date object:
36521 var dt = new Date('5/4/06');
36522 dateField.setValue(dt);
36524 //Pass a date string (default format):
36525 dateField.setValue('5/4/06');
36527 //Pass a date string (custom format):
36528 dateField.format = 'Y-m-d';
36529 dateField.setValue('2006-5-4');
36531 * @param {String/Date} date The date or valid date string
36533 setValue : function(date){
36534 if (this.hiddenField) {
36535 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36537 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36541 parseDate : function(value){
36542 if(!value || value instanceof Date){
36545 var v = Date.parseDate(value, this.format);
36546 if(!v && this.altFormats){
36547 if(!this.altFormatsArray){
36548 this.altFormatsArray = this.altFormats.split("|");
36550 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36551 v = Date.parseDate(value, this.altFormatsArray[i]);
36558 formatDate : function(date, fmt){
36559 return (!date || !(date instanceof Date)) ?
36560 date : date.dateFormat(fmt || this.format);
36565 select: function(m, d){
36567 this.fireEvent('select', this, d);
36569 show : function(){ // retain focus styling
36573 this.focus.defer(10, this);
36574 var ml = this.menuListeners;
36575 this.menu.un("select", ml.select, this);
36576 this.menu.un("show", ml.show, this);
36577 this.menu.un("hide", ml.hide, this);
36582 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36583 onTriggerClick : function(){
36587 if(this.menu == null){
36588 this.menu = new Roo.menu.DateMenu();
36590 Roo.apply(this.menu.picker, {
36591 showClear: this.allowBlank,
36592 minDate : this.minValue,
36593 maxDate : this.maxValue,
36594 disabledDatesRE : this.ddMatch,
36595 disabledDatesText : this.disabledDatesText,
36596 disabledDays : this.disabledDays,
36597 disabledDaysText : this.disabledDaysText,
36598 format : this.format,
36599 minText : String.format(this.minText, this.formatDate(this.minValue)),
36600 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36602 this.menu.on(Roo.apply({}, this.menuListeners, {
36605 this.menu.picker.setValue(this.getValue() || new Date());
36606 this.menu.show(this.el, "tl-bl?");
36609 beforeBlur : function(){
36610 var v = this.parseDate(this.getRawValue());
36616 /** @cfg {Boolean} grow @hide */
36617 /** @cfg {Number} growMin @hide */
36618 /** @cfg {Number} growMax @hide */
36625 * Ext JS Library 1.1.1
36626 * Copyright(c) 2006-2007, Ext JS, LLC.
36628 * Originally Released Under LGPL - original licence link has changed is not relivant.
36631 * <script type="text/javascript">
36636 * @class Roo.form.ComboBox
36637 * @extends Roo.form.TriggerField
36638 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36640 * Create a new ComboBox.
36641 * @param {Object} config Configuration options
36643 Roo.form.ComboBox = function(config){
36644 Roo.form.ComboBox.superclass.constructor.call(this, config);
36648 * Fires when the dropdown list is expanded
36649 * @param {Roo.form.ComboBox} combo This combo box
36654 * Fires when the dropdown list is collapsed
36655 * @param {Roo.form.ComboBox} combo This combo box
36659 * @event beforeselect
36660 * Fires before a list item is selected. Return false to cancel the selection.
36661 * @param {Roo.form.ComboBox} combo This combo box
36662 * @param {Roo.data.Record} record The data record returned from the underlying store
36663 * @param {Number} index The index of the selected item in the dropdown list
36665 'beforeselect' : true,
36668 * Fires when a list item is selected
36669 * @param {Roo.form.ComboBox} combo This combo box
36670 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36671 * @param {Number} index The index of the selected item in the dropdown list
36675 * @event beforequery
36676 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36677 * The event object passed has these properties:
36678 * @param {Roo.form.ComboBox} combo This combo box
36679 * @param {String} query The query
36680 * @param {Boolean} forceAll true to force "all" query
36681 * @param {Boolean} cancel true to cancel the query
36682 * @param {Object} e The query event object
36684 'beforequery': true
36686 if(this.transform){
36687 this.allowDomMove = false;
36688 var s = Roo.getDom(this.transform);
36689 if(!this.hiddenName){
36690 this.hiddenName = s.name;
36693 this.mode = 'local';
36694 var d = [], opts = s.options;
36695 for(var i = 0, len = opts.length;i < len; i++){
36697 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
36699 this.value = value;
36701 d.push([value, o.text]);
36703 this.store = new Roo.data.SimpleStore({
36705 fields: ['value', 'text'],
36708 this.valueField = 'value';
36709 this.displayField = 'text';
36711 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
36712 if(!this.lazyRender){
36713 this.target = true;
36714 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
36715 s.parentNode.removeChild(s); // remove it
36716 this.render(this.el.parentNode);
36718 s.parentNode.removeChild(s); // remove it
36723 this.store = Roo.factory(this.store, Roo.data);
36726 this.selectedIndex = -1;
36727 if(this.mode == 'local'){
36728 if(config.queryDelay === undefined){
36729 this.queryDelay = 10;
36731 if(config.minChars === undefined){
36737 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
36739 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
36742 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
36743 * rendering into an Roo.Editor, defaults to false)
36746 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
36747 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
36750 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
36753 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
36754 * the dropdown list (defaults to undefined, with no header element)
36758 * @cfg {String/Roo.Template} tpl The template to use to render the output
36762 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
36764 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
36766 listWidth: undefined,
36768 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
36769 * mode = 'remote' or 'text' if mode = 'local')
36771 displayField: undefined,
36773 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
36774 * mode = 'remote' or 'value' if mode = 'local').
36775 * Note: use of a valueField requires the user make a selection
36776 * in order for a value to be mapped.
36778 valueField: undefined,
36780 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
36781 * field's data value (defaults to the underlying DOM element's name)
36783 hiddenName: undefined,
36785 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
36789 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
36791 selectedClass: 'x-combo-selected',
36793 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36794 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
36795 * which displays a downward arrow icon).
36797 triggerClass : 'x-form-arrow-trigger',
36799 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
36803 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
36804 * anchor positions (defaults to 'tl-bl')
36806 listAlign: 'tl-bl?',
36808 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
36812 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
36813 * query specified by the allQuery config option (defaults to 'query')
36815 triggerAction: 'query',
36817 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
36818 * (defaults to 4, does not apply if editable = false)
36822 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
36823 * delay (typeAheadDelay) if it matches a known value (defaults to false)
36827 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
36828 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
36832 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
36833 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
36837 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
36838 * when editable = true (defaults to false)
36840 selectOnFocus:false,
36842 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
36844 queryParam: 'query',
36846 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
36847 * when mode = 'remote' (defaults to 'Loading...')
36849 loadingText: 'Loading...',
36851 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
36855 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
36859 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
36860 * traditional select (defaults to true)
36864 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
36868 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
36872 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
36873 * listWidth has a higher value)
36877 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
36878 * allow the user to set arbitrary text into the field (defaults to false)
36880 forceSelection:false,
36882 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
36883 * if typeAhead = true (defaults to 250)
36885 typeAheadDelay : 250,
36887 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
36888 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
36890 valueNotFoundText : undefined,
36892 * @cfg {bool} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
36894 blockFocus : false,
36897 * @cfg {bool} disableClear Disable showing of clear button.
36899 disableClear : false,
36902 onRender : function(ct, position){
36903 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
36904 if(this.hiddenName){
36905 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
36907 this.hiddenField.value =
36908 this.hiddenValue !== undefined ? this.hiddenValue :
36909 this.value !== undefined ? this.value : '';
36911 // prevent input submission
36912 this.el.dom.removeAttribute('name');
36915 this.el.dom.setAttribute('autocomplete', 'off');
36918 var cls = 'x-combo-list';
36920 this.list = new Roo.Layer({
36921 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
36924 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
36925 this.list.setWidth(lw);
36926 this.list.swallowEvent('mousewheel');
36927 this.assetHeight = 0;
36930 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
36931 this.assetHeight += this.header.getHeight();
36934 this.innerList = this.list.createChild({cls:cls+'-inner'});
36935 this.innerList.on('mouseover', this.onViewOver, this);
36936 this.innerList.on('mousemove', this.onViewMove, this);
36937 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
36939 if(this.allowBlank && !this.pageSize && !this.disableClear){
36940 this.footer = this.list.createChild({cls:cls+'-ft'});
36941 this.pageTb = new Roo.Toolbar(this.footer);
36945 this.footer = this.list.createChild({cls:cls+'-ft'});
36946 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
36947 {pageSize: this.pageSize});
36951 if (this.pageTb && this.allowBlank && !this.disableClear) {
36953 this.pageTb.add(new Roo.Toolbar.Fill(), {
36954 cls: 'x-btn-icon x-btn-clear',
36956 handler: function()
36959 _this.clearValue();
36960 _this.onSelect(false, -1);
36965 this.assetHeight += this.footer.getHeight();
36970 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
36973 this.view = new Roo.View(this.innerList, this.tpl, {
36974 singleSelect:true, store: this.store, selectedClass: this.selectedClass
36977 this.view.on('click', this.onViewClick, this);
36979 this.store.on('beforeload', this.onBeforeLoad, this);
36980 this.store.on('load', this.onLoad, this);
36981 this.store.on('loadexception', this.collapse, this);
36983 if(this.resizable){
36984 this.resizer = new Roo.Resizable(this.list, {
36985 pinned:true, handles:'se'
36987 this.resizer.on('resize', function(r, w, h){
36988 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
36989 this.listWidth = w;
36990 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
36991 this.restrictHeight();
36993 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
36995 if(!this.editable){
36996 this.editable = true;
36997 this.setEditable(false);
37002 initEvents : function(){
37003 Roo.form.ComboBox.superclass.initEvents.call(this);
37005 this.keyNav = new Roo.KeyNav(this.el, {
37006 "up" : function(e){
37007 this.inKeyMode = true;
37011 "down" : function(e){
37012 if(!this.isExpanded()){
37013 this.onTriggerClick();
37015 this.inKeyMode = true;
37020 "enter" : function(e){
37021 this.onViewClick();
37025 "esc" : function(e){
37029 "tab" : function(e){
37030 this.onViewClick(false);
37036 doRelay : function(foo, bar, hname){
37037 if(hname == 'down' || this.scope.isExpanded()){
37038 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37045 this.queryDelay = Math.max(this.queryDelay || 10,
37046 this.mode == 'local' ? 10 : 250);
37047 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37048 if(this.typeAhead){
37049 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37051 if(this.editable !== false){
37052 this.el.on("keyup", this.onKeyUp, this);
37054 if(this.forceSelection){
37055 this.on('blur', this.doForce, this);
37059 onDestroy : function(){
37061 this.view.setStore(null);
37062 this.view.el.removeAllListeners();
37063 this.view.el.remove();
37064 this.view.purgeListeners();
37067 this.list.destroy();
37070 this.store.un('beforeload', this.onBeforeLoad, this);
37071 this.store.un('load', this.onLoad, this);
37072 this.store.un('loadexception', this.collapse, this);
37074 Roo.form.ComboBox.superclass.onDestroy.call(this);
37078 fireKey : function(e){
37079 if(e.isNavKeyPress() && !this.list.isVisible()){
37080 this.fireEvent("specialkey", this, e);
37085 onResize: function(w, h){
37086 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37087 if(this.list && this.listWidth === undefined){
37088 var lw = Math.max(w, this.minListWidth);
37089 this.list.setWidth(lw);
37090 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37095 * Allow or prevent the user from directly editing the field text. If false is passed,
37096 * the user will only be able to select from the items defined in the dropdown list. This method
37097 * is the runtime equivalent of setting the 'editable' config option at config time.
37098 * @param {Boolean} value True to allow the user to directly edit the field text
37100 setEditable : function(value){
37101 if(value == this.editable){
37104 this.editable = value;
37106 this.el.dom.setAttribute('readOnly', true);
37107 this.el.on('mousedown', this.onTriggerClick, this);
37108 this.el.addClass('x-combo-noedit');
37110 this.el.dom.setAttribute('readOnly', false);
37111 this.el.un('mousedown', this.onTriggerClick, this);
37112 this.el.removeClass('x-combo-noedit');
37117 onBeforeLoad : function(){
37118 if(!this.hasFocus){
37121 this.innerList.update(this.loadingText ?
37122 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37123 this.restrictHeight();
37124 this.selectedIndex = -1;
37128 onLoad : function(){
37129 if(!this.hasFocus){
37132 if(this.store.getCount() > 0){
37134 this.restrictHeight();
37135 if(this.lastQuery == this.allQuery){
37137 this.el.dom.select();
37139 if(!this.selectByValue(this.value, true)){
37140 this.select(0, true);
37144 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37145 this.taTask.delay(this.typeAheadDelay);
37149 this.onEmptyResults();
37155 onTypeAhead : function(){
37156 if(this.store.getCount() > 0){
37157 var r = this.store.getAt(0);
37158 var newValue = r.data[this.displayField];
37159 var len = newValue.length;
37160 var selStart = this.getRawValue().length;
37161 if(selStart != len){
37162 this.setRawValue(newValue);
37163 this.selectText(selStart, newValue.length);
37169 onSelect : function(record, index){
37170 if(this.fireEvent('beforeselect', this, record, index) !== false){
37171 this.setFromData(index > -1 ? record.data : false);
37173 this.fireEvent('select', this, record, index);
37178 * Returns the currently selected field value or empty string if no value is set.
37179 * @return {String} value The selected value
37181 getValue : function(){
37182 if(this.valueField){
37183 return typeof this.value != 'undefined' ? this.value : '';
37185 return Roo.form.ComboBox.superclass.getValue.call(this);
37190 * Clears any text/value currently set in the field
37192 clearValue : function(){
37193 if(this.hiddenField){
37194 this.hiddenField.value = '';
37197 this.setRawValue('');
37198 this.lastSelectionText = '';
37199 this.applyEmptyText();
37203 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37204 * will be displayed in the field. If the value does not match the data value of an existing item,
37205 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37206 * Otherwise the field will be blank (although the value will still be set).
37207 * @param {String} value The value to match
37209 setValue : function(v){
37211 if(this.valueField){
37212 var r = this.findRecord(this.valueField, v);
37214 text = r.data[this.displayField];
37215 }else if(this.valueNotFoundText !== undefined){
37216 text = this.valueNotFoundText;
37219 this.lastSelectionText = text;
37220 if(this.hiddenField){
37221 this.hiddenField.value = v;
37223 Roo.form.ComboBox.superclass.setValue.call(this, text);
37227 * @property {Object} the last set data for the element
37232 * Sets the value of the field based on a object which is related to the record format for the store.
37233 * @param {Object} value the value to set as. or false on reset?
37235 setFromData : function(o){
37236 var dv = ''; // display value
37237 var vv = ''; // value value..
37239 if (this.displayField) {
37240 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37242 // this is an error condition!!!
37243 console.log('no value field set for '+ this.name);
37246 if(this.valueField){
37247 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37249 if(this.hiddenField){
37250 this.hiddenField.value = vv;
37252 this.lastSelectionText = dv;
37253 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37257 // no hidden field.. - we store the value in 'value', but still display
37258 // display field!!!!
37259 this.lastSelectionText = dv;
37260 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37266 reset : function(){
37267 // overridden so that last data is reset..
37268 this.setValue(this.originalValue);
37269 this.clearInvalid();
37270 this.lastData = false;
37273 findRecord : function(prop, value){
37275 if(this.store.getCount() > 0){
37276 this.store.each(function(r){
37277 if(r.data[prop] == value){
37287 onViewMove : function(e, t){
37288 this.inKeyMode = false;
37292 onViewOver : function(e, t){
37293 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37296 var item = this.view.findItemFromChild(t);
37298 var index = this.view.indexOf(item);
37299 this.select(index, false);
37304 onViewClick : function(doFocus){
37305 var index = this.view.getSelectedIndexes()[0];
37306 var r = this.store.getAt(index);
37308 this.onSelect(r, index);
37310 if(doFocus !== false && !this.blockFocus){
37316 restrictHeight : function(){
37317 this.innerList.dom.style.height = '';
37318 var inner = this.innerList.dom;
37319 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37320 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37321 this.list.beginUpdate();
37322 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37323 this.list.alignTo(this.el, this.listAlign);
37324 this.list.endUpdate();
37328 onEmptyResults : function(){
37333 * Returns true if the dropdown list is expanded, else false.
37335 isExpanded : function(){
37336 return this.list.isVisible();
37340 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37341 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37342 * @param {String} value The data value of the item to select
37343 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37344 * selected item if it is not currently in view (defaults to true)
37345 * @return {Boolean} True if the value matched an item in the list, else false
37347 selectByValue : function(v, scrollIntoView){
37348 if(v !== undefined && v !== null){
37349 var r = this.findRecord(this.valueField || this.displayField, v);
37351 this.select(this.store.indexOf(r), scrollIntoView);
37359 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37360 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37361 * @param {Number} index The zero-based index of the list item to select
37362 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37363 * selected item if it is not currently in view (defaults to true)
37365 select : function(index, scrollIntoView){
37366 this.selectedIndex = index;
37367 this.view.select(index);
37368 if(scrollIntoView !== false){
37369 var el = this.view.getNode(index);
37371 this.innerList.scrollChildIntoView(el, false);
37377 selectNext : function(){
37378 var ct = this.store.getCount();
37380 if(this.selectedIndex == -1){
37382 }else if(this.selectedIndex < ct-1){
37383 this.select(this.selectedIndex+1);
37389 selectPrev : function(){
37390 var ct = this.store.getCount();
37392 if(this.selectedIndex == -1){
37394 }else if(this.selectedIndex != 0){
37395 this.select(this.selectedIndex-1);
37401 onKeyUp : function(e){
37402 if(this.editable !== false && !e.isSpecialKey()){
37403 this.lastKey = e.getKey();
37404 this.dqTask.delay(this.queryDelay);
37409 validateBlur : function(){
37410 return !this.list || !this.list.isVisible();
37414 initQuery : function(){
37415 this.doQuery(this.getRawValue());
37419 doForce : function(){
37420 if(this.el.dom.value.length > 0){
37421 this.el.dom.value =
37422 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37423 this.applyEmptyText();
37428 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37429 * query allowing the query action to be canceled if needed.
37430 * @param {String} query The SQL query to execute
37431 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37432 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37433 * saved in the current store (defaults to false)
37435 doQuery : function(q, forceAll){
37436 if(q === undefined || q === null){
37441 forceAll: forceAll,
37445 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37449 forceAll = qe.forceAll;
37450 if(forceAll === true || (q.length >= this.minChars)){
37451 if(this.lastQuery != q){
37452 this.lastQuery = q;
37453 if(this.mode == 'local'){
37454 this.selectedIndex = -1;
37456 this.store.clearFilter();
37458 this.store.filter(this.displayField, q);
37462 this.store.baseParams[this.queryParam] = q;
37464 params: this.getParams(q)
37469 this.selectedIndex = -1;
37476 getParams : function(q){
37478 //p[this.queryParam] = q;
37481 p.limit = this.pageSize;
37487 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37489 collapse : function(){
37490 if(!this.isExpanded()){
37494 Roo.get(document).un('mousedown', this.collapseIf, this);
37495 Roo.get(document).un('mousewheel', this.collapseIf, this);
37496 this.fireEvent('collapse', this);
37500 collapseIf : function(e){
37501 if(!e.within(this.wrap) && !e.within(this.list)){
37507 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37509 expand : function(){
37510 if(this.isExpanded() || !this.hasFocus){
37513 this.list.alignTo(this.el, this.listAlign);
37515 Roo.get(document).on('mousedown', this.collapseIf, this);
37516 Roo.get(document).on('mousewheel', this.collapseIf, this);
37517 this.fireEvent('expand', this);
37521 // Implements the default empty TriggerField.onTriggerClick function
37522 onTriggerClick : function(){
37526 if(this.isExpanded()){
37528 if (!this.blockFocus) {
37533 this.hasFocus = true;
37534 if(this.triggerAction == 'all') {
37535 this.doQuery(this.allQuery, true);
37537 this.doQuery(this.getRawValue());
37539 if (!this.blockFocus) {
37546 * @cfg {Boolean} grow
37550 * @cfg {Number} growMin
37554 * @cfg {Number} growMax
37563 * Ext JS Library 1.1.1
37564 * Copyright(c) 2006-2007, Ext JS, LLC.
37566 * Originally Released Under LGPL - original licence link has changed is not relivant.
37569 * <script type="text/javascript">
37572 * @class Roo.form.Checkbox
37573 * @extends Roo.form.Field
37574 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
37576 * Creates a new Checkbox
37577 * @param {Object} config Configuration options
37579 Roo.form.Checkbox = function(config){
37580 Roo.form.Checkbox.superclass.constructor.call(this, config);
37584 * Fires when the checkbox is checked or unchecked.
37585 * @param {Roo.form.Checkbox} this This checkbox
37586 * @param {Boolean} checked The new checked value
37592 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
37594 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
37596 focusClass : undefined,
37598 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
37600 fieldClass: "x-form-field",
37602 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
37606 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37607 * {tag: "input", type: "checkbox", autocomplete: "off"})
37609 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
37611 * @cfg {String} boxLabel The text that appears beside the checkbox
37615 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
37619 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
37621 valueOff: '0', // value when not checked..
37623 actionMode : 'viewEl',
37626 itemCls : 'x-menu-check-item x-form-item',
37627 groupClass : 'x-menu-group-item',
37628 inputType : 'hidden',
37631 inSetChecked: false, // check that we are not calling self...
37633 inputElement: false, // real input element?
37634 basedOn: false, // ????
37636 isFormField: true, // not sure where this is needed!!!!
37638 onResize : function(){
37639 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
37640 if(!this.boxLabel){
37641 this.el.alignTo(this.wrap, 'c-c');
37645 initEvents : function(){
37646 Roo.form.Checkbox.superclass.initEvents.call(this);
37647 this.el.on("click", this.onClick, this);
37648 this.el.on("change", this.onClick, this);
37652 getResizeEl : function(){
37656 getPositionEl : function(){
37661 onRender : function(ct, position){
37662 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
37664 if(this.inputValue !== undefined){
37665 this.el.dom.value = this.inputValue;
37668 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
37669 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
37670 var viewEl = this.wrap.createChild({
37671 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
37672 this.viewEl = viewEl;
37673 this.wrap.on('click', this.onClick, this);
37675 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
37676 this.el.on('propertychange', this.setFromHidden, this); //ie
37681 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
37682 // viewEl.on('click', this.onClick, this);
37684 //if(this.checked){
37685 this.setChecked(this.checked);
37687 //this.checked = this.el.dom;
37693 initValue : Roo.emptyFn,
37696 * Returns the checked state of the checkbox.
37697 * @return {Boolean} True if checked, else false
37699 getValue : function(){
37701 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
37703 return this.valueOff;
37708 onClick : function(){
37709 this.setChecked(!this.checked);
37711 //if(this.el.dom.checked != this.checked){
37712 // this.setValue(this.el.dom.checked);
37717 * Sets the checked state of the checkbox.
37718 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
37720 setValue : function(v,suppressEvent){
37721 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
37722 //if(this.el && this.el.dom){
37723 // this.el.dom.checked = this.checked;
37724 // this.el.dom.defaultChecked = this.checked;
37726 this.setChecked(v === this.inputValue);
37727 //this.fireEvent("check", this, this.checked);
37730 setChecked : function(state,suppressEvent)
37732 if (this.inSetChecked) {
37733 this.checked = state;
37739 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
37741 this.checked = state;
37742 if(suppressEvent !== true){
37743 this.fireEvent('checkchange', this, state);
37745 this.inSetChecked = true;
37746 this.el.dom.value = state ? this.inputValue : this.valueOff;
37747 this.inSetChecked = false;
37750 // handle setting of hidden value by some other method!!?!?
37751 setFromHidden: function()
37756 //console.log("SET FROM HIDDEN");
37757 //alert('setFrom hidden');
37758 this.setValue(this.el.dom.value);
37761 onDestroy : function()
37764 Roo.get(this.viewEl).remove();
37767 Roo.form.Checkbox.superclass.onDestroy.call(this);
37772 * Ext JS Library 1.1.1
37773 * Copyright(c) 2006-2007, Ext JS, LLC.
37775 * Originally Released Under LGPL - original licence link has changed is not relivant.
37778 * <script type="text/javascript">
37782 * @class Roo.form.Radio
37783 * @extends Roo.form.Checkbox
37784 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
37785 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
37787 * Creates a new Radio
37788 * @param {Object} config Configuration options
37790 Roo.form.Radio = function(){
37791 Roo.form.Radio.superclass.constructor.apply(this, arguments);
37793 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
37794 inputType: 'radio',
37797 * If this radio is part of a group, it will return the selected value
37800 getGroupValue : function(){
37801 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
37803 });//<script type="text/javascript">
37806 * Ext JS Library 1.1.1
37807 * Copyright(c) 2006-2007, Ext JS, LLC.
37808 * licensing@extjs.com
37810 * http://www.extjs.com/license
37816 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
37817 * - IE ? - no idea how much works there.
37825 * @class Ext.form.HtmlEditor
37826 * @extends Ext.form.Field
37827 * Provides a lightweight HTML Editor component.
37828 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
37830 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
37831 * supported by this editor.</b><br/><br/>
37832 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
37833 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
37835 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
37837 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
37841 * @cfg {String} createLinkText The default text for the create link prompt
37843 createLinkText : 'Please enter the URL for the link:',
37845 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
37847 defaultLinkValue : 'http:/'+'/',
37853 // private properties
37854 validationEvent : false,
37856 initialized : false,
37858 sourceEditMode : false,
37859 onFocus : Roo.emptyFn,
37861 hideMode:'offsets',
37862 defaultAutoCreate : {
37864 style:"width:500px;height:300px;",
37865 autocomplete: "off"
37869 initComponent : function(){
37872 * @event initialize
37873 * Fires when the editor is fully initialized (including the iframe)
37874 * @param {HtmlEditor} this
37879 * Fires when the editor is first receives the focus. Any insertion must wait
37880 * until after this event.
37881 * @param {HtmlEditor} this
37885 * @event beforesync
37886 * Fires before the textarea is updated with content from the editor iframe. Return false
37887 * to cancel the sync.
37888 * @param {HtmlEditor} this
37889 * @param {String} html
37893 * @event beforepush
37894 * Fires before the iframe editor is updated with content from the textarea. Return false
37895 * to cancel the push.
37896 * @param {HtmlEditor} this
37897 * @param {String} html
37902 * Fires when the textarea is updated with content from the editor iframe.
37903 * @param {HtmlEditor} this
37904 * @param {String} html
37909 * Fires when the iframe editor is updated with content from the textarea.
37910 * @param {HtmlEditor} this
37911 * @param {String} html
37915 * @event editmodechange
37916 * Fires when the editor switches edit modes
37917 * @param {HtmlEditor} this
37918 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
37920 editmodechange: true,
37922 * @event editorevent
37923 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
37924 * @param {HtmlEditor} this
37931 * Protected method that will not generally be called directly. It
37932 * is called when the editor creates its toolbar. Override this method if you need to
37933 * add custom toolbar buttons.
37934 * @param {HtmlEditor} editor
37936 createToolbar : function(editor){
37937 if (!editor.toolbars || !editor.toolbars.length) {
37938 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
37941 for (var i =0 ; i < editor.toolbars.length;i++) {
37942 editor.toolbars[i].init(editor);
37949 * Protected method that will not generally be called directly. It
37950 * is called when the editor initializes the iframe with HTML contents. Override this method if you
37951 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
37953 getDocMarkup : function(){
37954 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
37958 onRender : function(ct, position){
37959 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
37960 this.el.dom.style.border = '0 none';
37961 this.el.dom.setAttribute('tabIndex', -1);
37962 this.el.addClass('x-hidden');
37963 if(Roo.isIE){ // fix IE 1px bogus margin
37964 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
37966 this.wrap = this.el.wrap({
37967 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
37970 this.frameId = Roo.id();
37971 this.createToolbar(this);
37978 var iframe = this.wrap.createChild({
37981 name: this.frameId,
37982 frameBorder : 'no',
37983 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
37986 // console.log(iframe);
37987 //this.wrap.dom.appendChild(iframe);
37989 this.iframe = iframe.dom;
37991 this.assignDocWin();
37993 this.doc.designMode = 'on';
37996 this.doc.write(this.getDocMarkup());
38000 var task = { // must defer to wait for browser to be ready
38002 //console.log("run task?" + this.doc.readyState);
38003 this.assignDocWin();
38004 if(this.doc.body || this.doc.readyState == 'complete'){
38008 this.doc.designMode="on";
38012 Roo.TaskMgr.stop(task);
38013 this.initEditor.defer(10, this);
38020 Roo.TaskMgr.start(task);
38023 this.setSize(this.el.getSize());
38028 onResize : function(w, h){
38029 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38030 if(this.el && this.iframe){
38031 if(typeof w == 'number'){
38032 var aw = w - this.wrap.getFrameWidth('lr');
38033 this.el.setWidth(this.adjustWidth('textarea', aw));
38034 this.iframe.style.width = aw + 'px';
38036 if(typeof h == 'number'){
38038 for (var i =0; i < this.toolbars.length;i++) {
38039 // fixme - ask toolbars for heights?
38040 tbh += this.toolbars[i].tb.el.getHeight();
38046 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38047 this.el.setHeight(this.adjustWidth('textarea', ah));
38048 this.iframe.style.height = ah + 'px';
38050 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38057 * Toggles the editor between standard and source edit mode.
38058 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38060 toggleSourceEdit : function(sourceEditMode){
38062 this.sourceEditMode = sourceEditMode === true;
38064 if(this.sourceEditMode){
38067 this.iframe.className = 'x-hidden';
38068 this.el.removeClass('x-hidden');
38069 this.el.dom.removeAttribute('tabIndex');
38074 this.iframe.className = '';
38075 this.el.addClass('x-hidden');
38076 this.el.dom.setAttribute('tabIndex', -1);
38079 this.setSize(this.wrap.getSize());
38080 this.fireEvent('editmodechange', this, this.sourceEditMode);
38083 // private used internally
38084 createLink : function(){
38085 var url = prompt(this.createLinkText, this.defaultLinkValue);
38086 if(url && url != 'http:/'+'/'){
38087 this.relayCmd('createlink', url);
38091 // private (for BoxComponent)
38092 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38094 // private (for BoxComponent)
38095 getResizeEl : function(){
38099 // private (for BoxComponent)
38100 getPositionEl : function(){
38105 initEvents : function(){
38106 this.originalValue = this.getValue();
38110 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38113 markInvalid : Roo.emptyFn,
38115 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38118 clearInvalid : Roo.emptyFn,
38120 setValue : function(v){
38121 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38126 * Protected method that will not generally be called directly. If you need/want
38127 * custom HTML cleanup, this is the method you should override.
38128 * @param {String} html The HTML to be cleaned
38129 * return {String} The cleaned HTML
38131 cleanHtml : function(html){
38132 html = String(html);
38133 if(html.length > 5){
38134 if(Roo.isSafari){ // strip safari nonsense
38135 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38138 if(html == ' '){
38145 * Protected method that will not generally be called directly. Syncs the contents
38146 * of the editor iframe with the textarea.
38148 syncValue : function(){
38149 if(this.initialized){
38150 var bd = (this.doc.body || this.doc.documentElement);
38151 var html = bd.innerHTML;
38153 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38154 var m = bs.match(/text-align:(.*?);/i);
38156 html = '<div style="'+m[0]+'">' + html + '</div>';
38159 html = this.cleanHtml(html);
38160 if(this.fireEvent('beforesync', this, html) !== false){
38161 this.el.dom.value = html;
38162 this.fireEvent('sync', this, html);
38168 * Protected method that will not generally be called directly. Pushes the value of the textarea
38169 * into the iframe editor.
38171 pushValue : function(){
38172 if(this.initialized){
38173 var v = this.el.dom.value;
38177 if(this.fireEvent('beforepush', this, v) !== false){
38178 (this.doc.body || this.doc.documentElement).innerHTML = v;
38179 this.fireEvent('push', this, v);
38185 deferFocus : function(){
38186 this.focus.defer(10, this);
38190 focus : function(){
38191 if(this.win && !this.sourceEditMode){
38198 assignDocWin: function()
38200 var iframe = this.iframe;
38203 this.doc = iframe.contentWindow.document;
38204 this.win = iframe.contentWindow;
38206 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38207 this.win = Roo.get(this.frameId).dom.contentWindow;
38212 initEditor : function(){
38213 //console.log("INIT EDITOR");
38214 this.assignDocWin();
38218 this.doc.designMode="on";
38220 this.doc.write(this.getDocMarkup());
38223 var dbody = (this.doc.body || this.doc.documentElement);
38224 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38225 // this copies styles from the containing element into thsi one..
38226 // not sure why we need all of this..
38227 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38228 ss['background-attachment'] = 'fixed'; // w3c
38229 dbody.bgProperties = 'fixed'; // ie
38230 Roo.DomHelper.applyStyles(dbody, ss);
38231 Roo.EventManager.on(this.doc, {
38232 'mousedown': this.onEditorEvent,
38233 'dblclick': this.onEditorEvent,
38234 'click': this.onEditorEvent,
38235 'keyup': this.onEditorEvent,
38240 Roo.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
38242 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38243 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38245 this.initialized = true;
38247 this.fireEvent('initialize', this);
38252 onDestroy : function(){
38258 for (var i =0; i < this.toolbars.length;i++) {
38259 // fixme - ask toolbars for heights?
38260 this.toolbars[i].onDestroy();
38263 this.wrap.dom.innerHTML = '';
38264 this.wrap.remove();
38269 onFirstFocus : function(){
38271 this.assignDocWin();
38274 this.activated = true;
38275 for (var i =0; i < this.toolbars.length;i++) {
38276 this.toolbars[i].onFirstFocus();
38279 if(Roo.isGecko){ // prevent silly gecko errors
38281 var s = this.win.getSelection();
38282 if(!s.focusNode || s.focusNode.nodeType != 3){
38283 var r = s.getRangeAt(0);
38284 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38289 this.execCmd('useCSS', true);
38290 this.execCmd('styleWithCSS', false);
38293 this.fireEvent('activate', this);
38297 adjustFont: function(btn){
38298 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38299 //if(Roo.isSafari){ // safari
38302 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38303 if(Roo.isSafari){ // safari
38304 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38305 v = (v < 10) ? 10 : v;
38306 v = (v > 48) ? 48 : v;
38307 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38312 v = Math.max(1, v+adjust);
38314 this.execCmd('FontSize', v );
38317 onEditorEvent : function(e){
38318 this.fireEvent('editorevent', this, e);
38319 // this.updateToolbar();
38323 insertTag : function(tg)
38325 // could be a bit smarter... -> wrap the current selected tRoo..
38327 this.execCmd("formatblock", tg);
38331 insertText : function(txt)
38335 range = this.createRange();
38336 range.deleteContents();
38337 //alert(Sender.getAttribute('label'));
38339 range.insertNode(this.doc.createTextNode(txt));
38343 relayBtnCmd : function(btn){
38344 this.relayCmd(btn.cmd);
38348 * Executes a Midas editor command on the editor document and performs necessary focus and
38349 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38350 * @param {String} cmd The Midas command
38351 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38353 relayCmd : function(cmd, value){
38355 this.execCmd(cmd, value);
38356 this.fireEvent('editorevent', this);
38357 //this.updateToolbar();
38362 * Executes a Midas editor command directly on the editor document.
38363 * For visual commands, you should use {@link #relayCmd} instead.
38364 * <b>This should only be called after the editor is initialized.</b>
38365 * @param {String} cmd The Midas command
38366 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38368 execCmd : function(cmd, value){
38369 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38374 applyCommand : function(e){
38376 var c = e.getCharCode(), cmd;
38378 c = String.fromCharCode(c);
38394 e.preventDefault();
38401 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38403 * @param {String} text
38405 insertAtCursor : function(text){
38406 if(!this.activated){
38411 var r = this.doc.selection.createRange();
38418 }else if(Roo.isGecko || Roo.isOpera){
38420 this.execCmd('InsertHTML', text);
38422 }else if(Roo.isSafari){
38423 this.execCmd('InsertText', text);
38429 fixKeys : function(){ // load time branching for fastest keydown performance
38431 return function(e){
38432 var k = e.getKey(), r;
38435 r = this.doc.selection.createRange();
38438 r.pasteHTML('    ');
38441 }else if(k == e.ENTER){
38442 r = this.doc.selection.createRange();
38444 var target = r.parentElement();
38445 if(!target || target.tagName.toLowerCase() != 'li'){
38447 r.pasteHTML('<br />');
38454 }else if(Roo.isOpera){
38455 return function(e){
38456 var k = e.getKey();
38460 this.execCmd('InsertHTML','    ');
38464 }else if(Roo.isSafari){
38465 return function(e){
38466 var k = e.getKey();
38469 this.execCmd('InsertText','\t');
38476 getAllAncestors: function()
38478 var p = this.getSelectedNode();
38481 a.push(p); // push blank onto stack..
38482 p = this.getParentElement();
38486 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38490 a.push(this.doc.body);
38494 lastSelNode : false,
38497 getSelection : function()
38499 this.assignDocWin();
38500 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38503 getSelectedNode: function()
38505 // this may only work on Gecko!!!
38507 // should we cache this!!!!
38512 var range = this.createRange(this.getSelection());
38515 var parent = range.parentElement();
38517 var testRange = range.duplicate();
38518 testRange.moveToElementText(parent);
38519 if (testRange.inRange(range)) {
38522 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38525 parent = parent.parentElement;
38531 var ar = range.endContainer.childNodes;
38533 ar = range.commonAncestorContainer.childNodes;
38534 //alert(ar.length);
38537 var other_nodes = [];
38538 var has_other_nodes = false;
38539 for (var i=0;i<ar.length;i++) {
38540 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
38543 // fullly contained node.
38545 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
38550 // probably selected..
38551 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
38552 other_nodes.push(ar[i]);
38555 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
38560 has_other_nodes = true;
38562 if (!nodes.length && other_nodes.length) {
38563 nodes= other_nodes;
38565 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
38571 createRange: function(sel)
38573 // this has strange effects when using with
38574 // top toolbar - not sure if it's a great idea.
38575 //this.editor.contentWindow.focus();
38576 if (typeof sel != "undefined") {
38578 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
38580 return this.doc.createRange();
38583 return this.doc.createRange();
38586 getParentElement: function()
38589 this.assignDocWin();
38590 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
38592 var range = this.createRange(sel);
38595 var p = range.commonAncestorContainer;
38596 while (p.nodeType == 3) { // text node
38608 // BC Hacks - cause I cant work out what i was trying to do..
38609 rangeIntersectsNode : function(range, node)
38611 var nodeRange = node.ownerDocument.createRange();
38613 nodeRange.selectNode(node);
38616 nodeRange.selectNodeContents(node);
38619 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
38620 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
38622 rangeCompareNode : function(range, node) {
38623 var nodeRange = node.ownerDocument.createRange();
38625 nodeRange.selectNode(node);
38627 nodeRange.selectNodeContents(node);
38629 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
38630 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
38632 if (nodeIsBefore && !nodeIsAfter)
38634 if (!nodeIsBefore && nodeIsAfter)
38636 if (nodeIsBefore && nodeIsAfter)
38644 // hide stuff that is not compatible
38658 * @event specialkey
38662 * @cfg {String} fieldClass @hide
38665 * @cfg {String} focusClass @hide
38668 * @cfg {String} autoCreate @hide
38671 * @cfg {String} inputType @hide
38674 * @cfg {String} invalidClass @hide
38677 * @cfg {String} invalidText @hide
38680 * @cfg {String} msgFx @hide
38683 * @cfg {String} validateOnBlur @hide
38685 });// <script type="text/javascript">
38688 * Ext JS Library 1.1.1
38689 * Copyright(c) 2006-2007, Ext JS, LLC.
38695 * @class Roo.form.HtmlEditorToolbar1
38700 new Roo.form.HtmlEditor({
38703 new Roo.form.HtmlEditorToolbar1({
38704 disable : { fonts: 1 , format: 1, ..., ... , ...],
38710 * @cfg {Object} disable List of elements to disable..
38711 * @cfg {Array} btns List of additional buttons.
38715 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
38718 Roo.form.HtmlEditor.ToolbarStandard = function(config)
38721 Roo.apply(this, config);
38722 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
38723 // dont call parent... till later.
38726 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
38734 * @cfg {Object} disable List of toolbar elements to disable
38739 * @cfg {Array} fontFamilies An array of available font families
38757 // "á" , ?? a acute?
38762 "°" // , // degrees
38764 // "é" , // e ecute
38765 // "ú" , // u ecute?
38768 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
38769 "input:submit", "input:button", "select", "textarea", "label" ],
38772 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
38774 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
38777 * @cfg {String} defaultFont default font to use.
38779 defaultFont: 'tahoma',
38781 fontSelect : false,
38784 formatCombo : false,
38786 init : function(editor)
38788 this.editor = editor;
38791 var fid = editor.frameId;
38793 function btn(id, toggle, handler){
38794 var xid = fid + '-'+ id ;
38798 cls : 'x-btn-icon x-edit-'+id,
38799 enableToggle:toggle !== false,
38800 scope: editor, // was editor...
38801 handler:handler||editor.relayBtnCmd,
38802 clickEvent:'mousedown',
38803 tooltip: etb.buttonTips[id] || undefined, ///tips ???
38810 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
38812 // stop form submits
38813 tb.el.on('click', function(e){
38814 e.preventDefault(); // what does this do?
38817 if(!this.disable.font && !Roo.isSafari){
38818 /* why no safari for fonts
38819 editor.fontSelect = tb.el.createChild({
38822 cls:'x-font-select',
38823 html: editor.createFontOptions()
38825 editor.fontSelect.on('change', function(){
38826 var font = editor.fontSelect.dom.value;
38827 editor.relayCmd('fontname', font);
38828 editor.deferFocus();
38831 editor.fontSelect.dom,
38836 if(!this.disable.formats){
38837 this.formatCombo = new Roo.form.ComboBox({
38838 store: new Roo.data.SimpleStore({
38841 data : this.formats // from states.js
38844 //autoCreate : {tag: "div", size: "20"},
38845 displayField:'tag',
38849 triggerAction: 'all',
38850 emptyText:'Add tag',
38851 selectOnFocus:true,
38854 'select': function(c, r, i) {
38855 editor.insertTag(r.get('tag'));
38861 tb.addField(this.formatCombo);
38865 if(!this.disable.format){
38872 if(!this.disable.fontSize){
38877 btn('increasefontsize', false, editor.adjustFont),
38878 btn('decreasefontsize', false, editor.adjustFont)
38883 if(this.disable.colors){
38886 id:editor.frameId +'-forecolor',
38887 cls:'x-btn-icon x-edit-forecolor',
38888 clickEvent:'mousedown',
38889 tooltip: this.buttonTips['forecolor'] || undefined,
38891 menu : new Roo.menu.ColorMenu({
38892 allowReselect: true,
38893 focus: Roo.emptyFn,
38896 selectHandler: function(cp, color){
38897 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
38898 editor.deferFocus();
38901 clickEvent:'mousedown'
38904 id:editor.frameId +'backcolor',
38905 cls:'x-btn-icon x-edit-backcolor',
38906 clickEvent:'mousedown',
38907 tooltip: this.buttonTips['backcolor'] || undefined,
38909 menu : new Roo.menu.ColorMenu({
38910 focus: Roo.emptyFn,
38913 allowReselect: true,
38914 selectHandler: function(cp, color){
38916 editor.execCmd('useCSS', false);
38917 editor.execCmd('hilitecolor', color);
38918 editor.execCmd('useCSS', true);
38919 editor.deferFocus();
38921 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
38922 Roo.isSafari || Roo.isIE ? '#'+color : color);
38923 editor.deferFocus();
38927 clickEvent:'mousedown'
38932 // now add all the items...
38935 if(!this.disable.alignments){
38938 btn('justifyleft'),
38939 btn('justifycenter'),
38940 btn('justifyright')
38944 //if(!Roo.isSafari){
38945 if(!this.disable.links){
38948 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
38952 if(!this.disable.lists){
38955 btn('insertorderedlist'),
38956 btn('insertunorderedlist')
38959 if(!this.disable.sourceEdit){
38962 btn('sourceedit', true, function(btn){
38963 this.toggleSourceEdit(btn.pressed);
38970 // special menu.. - needs to be tidied up..
38971 if (!this.disable.special) {
38974 cls: 'x-edit-none',
38979 for (var i =0; i < this.specialChars.length; i++) {
38980 smenu.menu.items.push({
38982 text: this.specialChars[i],
38983 handler: function(a,b) {
38984 editor.insertAtCursor(String.fromCharCode(a.text.replace('&#','').replace(';', '')));
38996 for(var i =0; i< this.btns.length;i++) {
38997 var b = this.btns[i];
38998 b.cls = 'x-edit-none';
39007 // disable everything...
39009 this.tb.items.each(function(item){
39010 if(item.id != editor.frameId+ '-sourceedit'){
39014 this.rendered = true;
39016 // the all the btns;
39017 editor.on('editorevent', this.updateToolbar, this);
39018 // other toolbars need to implement this..
39019 //editor.on('editmodechange', this.updateToolbar, this);
39025 * Protected method that will not generally be called directly. It triggers
39026 * a toolbar update by reading the markup state of the current selection in the editor.
39028 updateToolbar: function(){
39030 if(!this.editor.activated){
39031 this.editor.onFirstFocus();
39035 var btns = this.tb.items.map,
39036 doc = this.editor.doc,
39037 frameId = this.editor.frameId;
39039 if(!this.disable.font && !Roo.isSafari){
39041 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39042 if(name != this.fontSelect.dom.value){
39043 this.fontSelect.dom.value = name;
39047 if(!this.disable.format){
39048 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39049 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39050 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39052 if(!this.disable.alignments){
39053 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39054 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39055 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39057 if(!Roo.isSafari && !this.disable.lists){
39058 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39059 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39062 var ans = this.editor.getAllAncestors();
39063 if (this.formatCombo) {
39066 var store = this.formatCombo.store;
39067 this.formatCombo.setValue("");
39068 for (var i =0; i < ans.length;i++) {
39069 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), true).length) {
39071 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39079 // hides menus... - so this cant be on a menu...
39080 Roo.menu.MenuMgr.hideAll();
39082 //this.editorsyncValue();
39086 createFontOptions : function(){
39087 var buf = [], fs = this.fontFamilies, ff, lc;
39088 for(var i = 0, len = fs.length; i< len; i++){
39090 lc = ff.toLowerCase();
39092 '<option value="',lc,'" style="font-family:',ff,';"',
39093 (this.defaultFont == lc ? ' selected="true">' : '>'),
39098 return buf.join('');
39101 toggleSourceEdit : function(sourceEditMode){
39102 if(sourceEditMode === undefined){
39103 sourceEditMode = !this.sourceEditMode;
39105 this.sourceEditMode = sourceEditMode === true;
39106 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39107 // just toggle the button?
39108 if(btn.pressed !== this.editor.sourceEditMode){
39109 btn.toggle(this.editor.sourceEditMode);
39113 if(this.sourceEditMode){
39114 this.tb.items.each(function(item){
39115 if(item.cmd != 'sourceedit'){
39121 if(this.initialized){
39122 this.tb.items.each(function(item){
39128 // tell the editor that it's been pressed..
39129 this.editor.toggleSourceEdit(sourceEditMode);
39133 * Object collection of toolbar tooltips for the buttons in the editor. The key
39134 * is the command id associated with that button and the value is a valid QuickTips object.
39139 title: 'Bold (Ctrl+B)',
39140 text: 'Make the selected text bold.',
39141 cls: 'x-html-editor-tip'
39144 title: 'Italic (Ctrl+I)',
39145 text: 'Make the selected text italic.',
39146 cls: 'x-html-editor-tip'
39154 title: 'Bold (Ctrl+B)',
39155 text: 'Make the selected text bold.',
39156 cls: 'x-html-editor-tip'
39159 title: 'Italic (Ctrl+I)',
39160 text: 'Make the selected text italic.',
39161 cls: 'x-html-editor-tip'
39164 title: 'Underline (Ctrl+U)',
39165 text: 'Underline the selected text.',
39166 cls: 'x-html-editor-tip'
39168 increasefontsize : {
39169 title: 'Grow Text',
39170 text: 'Increase the font size.',
39171 cls: 'x-html-editor-tip'
39173 decreasefontsize : {
39174 title: 'Shrink Text',
39175 text: 'Decrease the font size.',
39176 cls: 'x-html-editor-tip'
39179 title: 'Text Highlight Color',
39180 text: 'Change the background color of the selected text.',
39181 cls: 'x-html-editor-tip'
39184 title: 'Font Color',
39185 text: 'Change the color of the selected text.',
39186 cls: 'x-html-editor-tip'
39189 title: 'Align Text Left',
39190 text: 'Align text to the left.',
39191 cls: 'x-html-editor-tip'
39194 title: 'Center Text',
39195 text: 'Center text in the editor.',
39196 cls: 'x-html-editor-tip'
39199 title: 'Align Text Right',
39200 text: 'Align text to the right.',
39201 cls: 'x-html-editor-tip'
39203 insertunorderedlist : {
39204 title: 'Bullet List',
39205 text: 'Start a bulleted list.',
39206 cls: 'x-html-editor-tip'
39208 insertorderedlist : {
39209 title: 'Numbered List',
39210 text: 'Start a numbered list.',
39211 cls: 'x-html-editor-tip'
39214 title: 'Hyperlink',
39215 text: 'Make the selected text a hyperlink.',
39216 cls: 'x-html-editor-tip'
39219 title: 'Source Edit',
39220 text: 'Switch to source editing mode.',
39221 cls: 'x-html-editor-tip'
39225 onDestroy : function(){
39228 this.tb.items.each(function(item){
39230 item.menu.removeAll();
39232 item.menu.el.destroy();
39240 onFirstFocus: function() {
39241 this.tb.items.each(function(item){
39250 // <script type="text/javascript">
39253 * Ext JS Library 1.1.1
39254 * Copyright(c) 2006-2007, Ext JS, LLC.
39261 * @class Roo.form.HtmlEditor.ToolbarContext
39266 new Roo.form.HtmlEditor({
39269 new Roo.form.HtmlEditor.ToolbarStandard(),
39270 new Roo.form.HtmlEditor.ToolbarContext()
39275 * @config : {Object} disable List of elements to disable.. (not done yet.)
39280 Roo.form.HtmlEditor.ToolbarContext = function(config)
39283 Roo.apply(this, config);
39284 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39285 // dont call parent... till later.
39287 Roo.form.HtmlEditor.ToolbarContext.types = {
39299 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39361 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39366 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
39430 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
39438 * @cfg {Object} disable List of toolbar elements to disable
39447 init : function(editor)
39449 this.editor = editor;
39452 var fid = editor.frameId;
39454 function btn(id, toggle, handler){
39455 var xid = fid + '-'+ id ;
39459 cls : 'x-btn-icon x-edit-'+id,
39460 enableToggle:toggle !== false,
39461 scope: editor, // was editor...
39462 handler:handler||editor.relayBtnCmd,
39463 clickEvent:'mousedown',
39464 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39468 // create a new element.
39469 var wdiv = editor.wrap.createChild({
39471 }, editor.wrap.dom.firstChild.nextSibling, true);
39473 // can we do this more than once??
39475 // stop form submits
39478 // disable everything...
39479 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39480 this.toolbars = {};
39482 for (var i in ty) {
39483 this.toolbars[i] = this.buildToolbar(ty[i],i);
39485 this.tb = this.toolbars.BODY;
39489 this.rendered = true;
39491 // the all the btns;
39492 editor.on('editorevent', this.updateToolbar, this);
39493 // other toolbars need to implement this..
39494 //editor.on('editmodechange', this.updateToolbar, this);
39500 * Protected method that will not generally be called directly. It triggers
39501 * a toolbar update by reading the markup state of the current selection in the editor.
39503 updateToolbar: function(){
39505 if(!this.editor.activated){
39506 this.editor.onFirstFocus();
39511 var ans = this.editor.getAllAncestors();
39514 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39515 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
39516 sel = sel ? sel : this.editor.doc.body;
39517 sel = sel.tagName.length ? sel : this.editor.doc.body;
39518 var tn = sel.tagName.toUpperCase();
39519 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
39520 tn = sel.tagName.toUpperCase();
39521 if (this.tb.name == tn) {
39522 return; // no change
39525 ///console.log("show: " + tn);
39526 this.tb = this.toolbars[tn];
39528 this.tb.fields.each(function(e) {
39529 e.setValue(sel.getAttribute(e.name));
39531 this.tb.selectedNode = sel;
39534 Roo.menu.MenuMgr.hideAll();
39536 //this.editorsyncValue();
39541 onDestroy : function(){
39544 this.tb.items.each(function(item){
39546 item.menu.removeAll();
39548 item.menu.el.destroy();
39556 onFirstFocus: function() {
39557 // need to do this for all the toolbars..
39558 this.tb.items.each(function(item){
39562 buildToolbar: function(tlist, nm)
39564 var editor = this.editor;
39565 // create a new element.
39566 var wdiv = editor.wrap.createChild({
39568 }, editor.wrap.dom.firstChild.nextSibling, true);
39571 var tb = new Roo.Toolbar(wdiv);
39572 tb.add(nm+ ": ");
39573 for (var i in tlist) {
39574 var item = tlist[i];
39575 tb.add(item.title + ": ");
39580 tb.addField( new Roo.form.ComboBox({
39581 store: new Roo.data.SimpleStore({
39584 data : item.opts // from states.js
39587 displayField:'val',
39591 triggerAction: 'all',
39592 emptyText:'Select',
39593 selectOnFocus:true,
39594 width: item.width ? item.width : 130,
39596 'select': function(c, r, i) {
39597 tb.selectedNode.setAttribute(c.name, r.get('val'));
39608 tb.addField( new Roo.form.TextField({
39611 //allowBlank:false,
39616 tb.addField( new Roo.form.TextField({
39622 'change' : function(f, nv, ov) {
39623 tb.selectedNode.setAttribute(f.name, nv);
39629 tb.el.on('click', function(e){
39630 e.preventDefault(); // what does this do?
39632 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
39635 // dont need to disable them... as they will get hidden
39652 * Ext JS Library 1.1.1
39653 * Copyright(c) 2006-2007, Ext JS, LLC.
39655 * Originally Released Under LGPL - original licence link has changed is not relivant.
39658 * <script type="text/javascript">
39662 * @class Roo.form.BasicForm
39663 * @extends Roo.util.Observable
39664 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
39666 * @param {String/HTMLElement/Roo.Element} el The form element or its id
39667 * @param {Object} config Configuration options
39669 Roo.form.BasicForm = function(el, config){
39670 this.allItems = [];
39671 this.childForms = [];
39672 Roo.apply(this, config);
39674 * The Roo.form.Field items in this form.
39675 * @type MixedCollection
39679 this.items = new Roo.util.MixedCollection(false, function(o){
39680 return o.id || (o.id = Roo.id());
39684 * @event beforeaction
39685 * Fires before any action is performed. Return false to cancel the action.
39686 * @param {Form} this
39687 * @param {Action} action The action to be performed
39689 beforeaction: true,
39691 * @event actionfailed
39692 * Fires when an action fails.
39693 * @param {Form} this
39694 * @param {Action} action The action that failed
39696 actionfailed : true,
39698 * @event actioncomplete
39699 * Fires when an action is completed.
39700 * @param {Form} this
39701 * @param {Action} action The action that completed
39703 actioncomplete : true
39708 Roo.form.BasicForm.superclass.constructor.call(this);
39711 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
39713 * @cfg {String} method
39714 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
39717 * @cfg {DataReader} reader
39718 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
39719 * This is optional as there is built-in support for processing JSON.
39722 * @cfg {DataReader} errorReader
39723 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
39724 * This is completely optional as there is built-in support for processing JSON.
39727 * @cfg {String} url
39728 * The URL to use for form actions if one isn't supplied in the action options.
39731 * @cfg {Boolean} fileUpload
39732 * Set to true if this form is a file upload.
39735 * @cfg {Object} baseParams
39736 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
39739 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
39744 activeAction : null,
39747 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
39748 * or setValues() data instead of when the form was first created.
39750 trackResetOnLoad : false,
39754 * childForms - used for multi-tab forms
39757 childForms : false,
39760 * allItems - full list of fields.
39766 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
39767 * element by passing it or its id or mask the form itself by passing in true.
39770 waitMsgTarget : undefined,
39773 initEl : function(el){
39774 this.el = Roo.get(el);
39775 this.id = this.el.id || Roo.id();
39776 this.el.on('submit', this.onSubmit, this);
39777 this.el.addClass('x-form');
39781 onSubmit : function(e){
39786 * Returns true if client-side validation on the form is successful.
39789 isValid : function(){
39791 this.items.each(function(f){
39800 * Returns true if any fields in this form have changed since their original load.
39803 isDirty : function(){
39805 this.items.each(function(f){
39815 * Performs a predefined action (submit or load) or custom actions you define on this form.
39816 * @param {String} actionName The name of the action type
39817 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
39818 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
39819 * accept other config options):
39821 Property Type Description
39822 ---------------- --------------- ----------------------------------------------------------------------------------
39823 url String The url for the action (defaults to the form's url)
39824 method String The form method to use (defaults to the form's method, or POST if not defined)
39825 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
39826 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
39827 validate the form on the client (defaults to false)
39829 * @return {BasicForm} this
39831 doAction : function(action, options){
39832 if(typeof action == 'string'){
39833 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
39835 if(this.fireEvent('beforeaction', this, action) !== false){
39836 this.beforeAction(action);
39837 action.run.defer(100, action);
39843 * Shortcut to do a submit action.
39844 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39845 * @return {BasicForm} this
39847 submit : function(options){
39848 this.doAction('submit', options);
39853 * Shortcut to do a load action.
39854 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39855 * @return {BasicForm} this
39857 load : function(options){
39858 this.doAction('load', options);
39863 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
39864 * @param {Record} record The record to edit
39865 * @return {BasicForm} this
39867 updateRecord : function(record){
39868 record.beginEdit();
39869 var fs = record.fields;
39870 fs.each(function(f){
39871 var field = this.findField(f.name);
39873 record.set(f.name, field.getValue());
39881 * Loads an Roo.data.Record into this form.
39882 * @param {Record} record The record to load
39883 * @return {BasicForm} this
39885 loadRecord : function(record){
39886 this.setValues(record.data);
39891 beforeAction : function(action){
39892 var o = action.options;
39894 if(this.waitMsgTarget === true){
39895 this.el.mask(o.waitMsg, 'x-mask-loading');
39896 }else if(this.waitMsgTarget){
39897 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
39898 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
39900 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
39906 afterAction : function(action, success){
39907 this.activeAction = null;
39908 var o = action.options;
39910 if(this.waitMsgTarget === true){
39912 }else if(this.waitMsgTarget){
39913 this.waitMsgTarget.unmask();
39915 Roo.MessageBox.updateProgress(1);
39916 Roo.MessageBox.hide();
39923 Roo.callback(o.success, o.scope, [this, action]);
39924 this.fireEvent('actioncomplete', this, action);
39926 Roo.callback(o.failure, o.scope, [this, action]);
39927 this.fireEvent('actionfailed', this, action);
39932 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
39933 * @param {String} id The value to search for
39936 findField : function(id){
39937 var field = this.items.get(id);
39939 this.items.each(function(f){
39940 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
39946 return field || null;
39950 * Add a secondary form to this one,
39951 * Used to provide tabbed forms. One form is primary, with hidden values
39952 * which mirror the elements from the other forms.
39954 * @param {Roo.form.Form} form to add.
39957 addForm : function(form){
39959 this.childForms.push(form);
39960 Roo.each(form.allItems, function (fe) {
39962 if (this.findField(fe.name)) { // already added..
39965 this.add( new Roo.form.Hidden({
39972 * Mark fields in this form invalid in bulk.
39973 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
39974 * @return {BasicForm} this
39976 markInvalid : function(errors){
39977 if(errors instanceof Array){
39978 for(var i = 0, len = errors.length; i < len; i++){
39979 var fieldError = errors[i];
39980 var f = this.findField(fieldError.id);
39982 f.markInvalid(fieldError.msg);
39988 if(typeof errors[id] != 'function' && (field = this.findField(id))){
39989 field.markInvalid(errors[id]);
39993 Roo.each(this.childForms || [], function (f) {
39994 f.markInvalid(errors);
40001 * Set values for fields in this form in bulk.
40002 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40003 * @return {BasicForm} this
40005 setValues : function(values){
40006 if(values instanceof Array){ // array of objects
40007 for(var i = 0, len = values.length; i < len; i++){
40009 var f = this.findField(v.id);
40011 f.setValue(v.value);
40012 if(this.trackResetOnLoad){
40013 f.originalValue = f.getValue();
40017 }else{ // object hash
40020 if(typeof values[id] != 'function' && (field = this.findField(id))){
40022 if (field.setFromData &&
40023 field.valueField &&
40024 field.displayField &&
40025 // combos' with local stores can
40026 // be queried via setValue()
40027 // to set their value..
40028 (field.store && !field.store.isLocal)
40032 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40033 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40034 field.setFromData(sd);
40037 field.setValue(values[id]);
40041 if(this.trackResetOnLoad){
40042 field.originalValue = field.getValue();
40048 Roo.each(this.childForms || [], function (f) {
40049 f.setValues(values);
40056 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40057 * they are returned as an array.
40058 * @param {Boolean} asString
40061 getValues : function(asString){
40062 if (this.childForms) {
40063 // copy values from the child forms
40064 Roo.each(this.childForms, function (f) {
40066 Roo.each(f.allFields, function (e) {
40067 if (e.name && e.getValue && this.findField(e.name)) {
40068 this.findField(e.name).setValue(e.getValue());
40077 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40078 if(asString === true){
40081 return Roo.urlDecode(fs);
40085 * Clears all invalid messages in this form.
40086 * @return {BasicForm} this
40088 clearInvalid : function(){
40089 this.items.each(function(f){
40093 Roo.each(this.childForms || [], function (f) {
40102 * Resets this form.
40103 * @return {BasicForm} this
40105 reset : function(){
40106 this.items.each(function(f){
40110 Roo.each(this.childForms || [], function (f) {
40119 * Add Roo.form components to this form.
40120 * @param {Field} field1
40121 * @param {Field} field2 (optional)
40122 * @param {Field} etc (optional)
40123 * @return {BasicForm} this
40126 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40132 * Removes a field from the items collection (does NOT remove its markup).
40133 * @param {Field} field
40134 * @return {BasicForm} this
40136 remove : function(field){
40137 this.items.remove(field);
40142 * Looks at the fields in this form, checks them for an id attribute,
40143 * and calls applyTo on the existing dom element with that id.
40144 * @return {BasicForm} this
40146 render : function(){
40147 this.items.each(function(f){
40148 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40156 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40157 * @param {Object} values
40158 * @return {BasicForm} this
40160 applyToFields : function(o){
40161 this.items.each(function(f){
40168 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40169 * @param {Object} values
40170 * @return {BasicForm} this
40172 applyIfToFields : function(o){
40173 this.items.each(function(f){
40181 Roo.BasicForm = Roo.form.BasicForm;/*
40183 * Ext JS Library 1.1.1
40184 * Copyright(c) 2006-2007, Ext JS, LLC.
40186 * Originally Released Under LGPL - original licence link has changed is not relivant.
40189 * <script type="text/javascript">
40193 * @class Roo.form.Form
40194 * @extends Roo.form.BasicForm
40195 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40197 * @param {Object} config Configuration options
40199 Roo.form.Form = function(config){
40201 if (config.items) {
40202 xitems = config.items;
40203 delete config.items;
40207 Roo.form.Form.superclass.constructor.call(this, null, config);
40208 this.url = this.url || this.action;
40210 this.root = new Roo.form.Layout(Roo.applyIf({
40214 this.active = this.root;
40216 * Array of all the buttons that have been added to this form via {@link addButton}
40220 this.allItems = [];
40223 * @event clientvalidation
40224 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40225 * @param {Form} this
40226 * @param {Boolean} valid true if the form has passed client-side validation
40228 clientvalidation: true,
40231 * Fires when the form is rendered
40232 * @param {Roo.form.Form} form
40237 Roo.each(xitems, this.addxtype, this);
40243 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40245 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40248 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40251 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40253 buttonAlign:'center',
40256 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40261 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40262 * This property cascades to child containers if not set.
40267 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40268 * fires a looping event with that state. This is required to bind buttons to the valid
40269 * state using the config value formBind:true on the button.
40271 monitorValid : false,
40274 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40280 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40281 * fields are added and the column is closed. If no fields are passed the column remains open
40282 * until end() is called.
40283 * @param {Object} config The config to pass to the column
40284 * @param {Field} field1 (optional)
40285 * @param {Field} field2 (optional)
40286 * @param {Field} etc (optional)
40287 * @return Column The column container object
40289 column : function(c){
40290 var col = new Roo.form.Column(c);
40292 if(arguments.length > 1){ // duplicate code required because of Opera
40293 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40300 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40301 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40302 * until end() is called.
40303 * @param {Object} config The config to pass to the fieldset
40304 * @param {Field} field1 (optional)
40305 * @param {Field} field2 (optional)
40306 * @param {Field} etc (optional)
40307 * @return FieldSet The fieldset container object
40309 fieldset : function(c){
40310 var fs = new Roo.form.FieldSet(c);
40312 if(arguments.length > 1){ // duplicate code required because of Opera
40313 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40320 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40321 * fields are added and the container is closed. If no fields are passed the container remains open
40322 * until end() is called.
40323 * @param {Object} config The config to pass to the Layout
40324 * @param {Field} field1 (optional)
40325 * @param {Field} field2 (optional)
40326 * @param {Field} etc (optional)
40327 * @return Layout The container object
40329 container : function(c){
40330 var l = new Roo.form.Layout(c);
40332 if(arguments.length > 1){ // duplicate code required because of Opera
40333 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40340 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
40341 * @param {Object} container A Roo.form.Layout or subclass of Layout
40342 * @return {Form} this
40344 start : function(c){
40345 // cascade label info
40346 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
40347 this.active.stack.push(c);
40348 c.ownerCt = this.active;
40354 * Closes the current open container
40355 * @return {Form} this
40358 if(this.active == this.root){
40361 this.active = this.active.ownerCt;
40366 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
40367 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
40368 * as the label of the field.
40369 * @param {Field} field1
40370 * @param {Field} field2 (optional)
40371 * @param {Field} etc. (optional)
40372 * @return {Form} this
40375 this.active.stack.push.apply(this.active.stack, arguments);
40376 this.allItems.push.apply(this.allItems,arguments);
40378 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
40379 if(a[i].isFormField){
40384 Roo.form.Form.superclass.add.apply(this, r);
40394 * Find any element that has been added to a form, using it's ID or name
40395 * This can include framesets, columns etc. along with regular fields..
40396 * @param {String} id - id or name to find.
40398 * @return {Element} e - or false if nothing found.
40400 findbyId : function(id)
40406 Ext.each(this.allItems, function(f){
40407 if (f.id == id || f.name == id ){
40418 * Render this form into the passed container. This should only be called once!
40419 * @param {String/HTMLElement/Element} container The element this component should be rendered into
40420 * @return {Form} this
40422 render : function(ct){
40424 var o = this.autoCreate || {
40426 method : this.method || 'POST',
40427 id : this.id || Roo.id()
40429 this.initEl(ct.createChild(o));
40431 this.root.render(this.el);
40433 this.items.each(function(f){
40434 f.render('x-form-el-'+f.id);
40437 if(this.buttons.length > 0){
40438 // tables are required to maintain order and for correct IE layout
40439 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
40440 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
40441 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
40443 var tr = tb.getElementsByTagName('tr')[0];
40444 for(var i = 0, len = this.buttons.length; i < len; i++) {
40445 var b = this.buttons[i];
40446 var td = document.createElement('td');
40447 td.className = 'x-form-btn-td';
40448 b.render(tr.appendChild(td));
40451 if(this.monitorValid){ // initialize after render
40452 this.startMonitoring();
40454 this.fireEvent('rendered', this);
40459 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
40460 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
40461 * object or a valid Roo.DomHelper element config
40462 * @param {Function} handler The function called when the button is clicked
40463 * @param {Object} scope (optional) The scope of the handler function
40464 * @return {Roo.Button}
40466 addButton : function(config, handler, scope){
40470 minWidth: this.minButtonWidth,
40473 if(typeof config == "string"){
40476 Roo.apply(bc, config);
40478 var btn = new Roo.Button(null, bc);
40479 this.buttons.push(btn);
40484 * Adds a series of form elements (using the xtype property as the factory method.
40485 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
40486 * @param {Object} config
40489 addxtype : function()
40491 var ar = Array.prototype.slice.call(arguments, 0);
40493 for(var i = 0; i < ar.length; i++) {
40495 continue; // skip -- if this happends something invalid got sent, we
40496 // should ignore it, as basically that interface element will not show up
40497 // and that should be pretty obvious!!
40500 if (Roo.form[ar[i].xtype]) {
40502 var fe = Roo.factory(ar[i], Roo.form);
40508 fe.store.form = this;
40513 this.allItems.push(fe);
40514 if (fe.items && fe.addxtype) {
40515 fe.addxtype.apply(fe, fe.items);
40525 // console.log('adding ' + ar[i].xtype);
40527 if (ar[i].xtype == 'Button') {
40528 //console.log('adding button');
40529 //console.log(ar[i]);
40530 this.addButton(ar[i]);
40531 this.allItems.push(fe);
40535 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
40536 alert('end is not supported on xtype any more, use items');
40538 // //console.log('adding end');
40546 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
40547 * option "monitorValid"
40549 startMonitoring : function(){
40552 Roo.TaskMgr.start({
40553 run : this.bindHandler,
40554 interval : this.monitorPoll || 200,
40561 * Stops monitoring of the valid state of this form
40563 stopMonitoring : function(){
40564 this.bound = false;
40568 bindHandler : function(){
40570 return false; // stops binding
40573 this.items.each(function(f){
40574 if(!f.isValid(true)){
40579 for(var i = 0, len = this.buttons.length; i < len; i++){
40580 var btn = this.buttons[i];
40581 if(btn.formBind === true && btn.disabled === valid){
40582 btn.setDisabled(!valid);
40585 this.fireEvent('clientvalidation', this, valid);
40599 Roo.Form = Roo.form.Form;
40602 * Ext JS Library 1.1.1
40603 * Copyright(c) 2006-2007, Ext JS, LLC.
40605 * Originally Released Under LGPL - original licence link has changed is not relivant.
40608 * <script type="text/javascript">
40612 * @class Roo.form.Action
40613 * Internal Class used to handle form actions
40615 * @param {Roo.form.BasicForm} el The form element or its id
40616 * @param {Object} config Configuration options
40620 // define the action interface
40621 Roo.form.Action = function(form, options){
40623 this.options = options || {};
40626 * Client Validation Failed
40629 Roo.form.Action.CLIENT_INVALID = 'client';
40631 * Server Validation Failed
40634 Roo.form.Action.SERVER_INVALID = 'server';
40636 * Connect to Server Failed
40639 Roo.form.Action.CONNECT_FAILURE = 'connect';
40641 * Reading Data from Server Failed
40644 Roo.form.Action.LOAD_FAILURE = 'load';
40646 Roo.form.Action.prototype = {
40648 failureType : undefined,
40649 response : undefined,
40650 result : undefined,
40652 // interface method
40653 run : function(options){
40657 // interface method
40658 success : function(response){
40662 // interface method
40663 handleResponse : function(response){
40667 // default connection failure
40668 failure : function(response){
40669 this.response = response;
40670 this.failureType = Roo.form.Action.CONNECT_FAILURE;
40671 this.form.afterAction(this, false);
40674 processResponse : function(response){
40675 this.response = response;
40676 if(!response.responseText){
40679 this.result = this.handleResponse(response);
40680 return this.result;
40683 // utility functions used internally
40684 getUrl : function(appendParams){
40685 var url = this.options.url || this.form.url || this.form.el.dom.action;
40687 var p = this.getParams();
40689 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
40695 getMethod : function(){
40696 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
40699 getParams : function(){
40700 var bp = this.form.baseParams;
40701 var p = this.options.params;
40703 if(typeof p == "object"){
40704 p = Roo.urlEncode(Roo.applyIf(p, bp));
40705 }else if(typeof p == 'string' && bp){
40706 p += '&' + Roo.urlEncode(bp);
40709 p = Roo.urlEncode(bp);
40714 createCallback : function(){
40716 success: this.success,
40717 failure: this.failure,
40719 timeout: (this.form.timeout*1000),
40720 upload: this.form.fileUpload ? this.success : undefined
40725 Roo.form.Action.Submit = function(form, options){
40726 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
40729 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
40733 var o = this.options;
40734 var method = this.getMethod();
40735 var isPost = method == 'POST';
40736 if(o.clientValidation === false || this.form.isValid()){
40737 Roo.Ajax.request(Roo.apply(this.createCallback(), {
40738 form:this.form.el.dom,
40739 url:this.getUrl(!isPost),
40741 params:isPost ? this.getParams() : null,
40742 isUpload: this.form.fileUpload
40745 }else if (o.clientValidation !== false){ // client validation failed
40746 this.failureType = Roo.form.Action.CLIENT_INVALID;
40747 this.form.afterAction(this, false);
40751 success : function(response){
40752 var result = this.processResponse(response);
40753 if(result === true || result.success){
40754 this.form.afterAction(this, true);
40758 this.form.markInvalid(result.errors);
40759 this.failureType = Roo.form.Action.SERVER_INVALID;
40761 this.form.afterAction(this, false);
40764 handleResponse : function(response){
40765 if(this.form.errorReader){
40766 var rs = this.form.errorReader.read(response);
40769 for(var i = 0, len = rs.records.length; i < len; i++) {
40770 var r = rs.records[i];
40771 errors[i] = r.data;
40774 if(errors.length < 1){
40778 success : rs.success,
40784 ret = Roo.decode(response.responseText);
40788 errorMsg: "Failed to read server message: " + response.responseText,
40798 Roo.form.Action.Load = function(form, options){
40799 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
40800 this.reader = this.form.reader;
40803 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
40807 Roo.Ajax.request(Roo.apply(
40808 this.createCallback(), {
40809 method:this.getMethod(),
40810 url:this.getUrl(false),
40811 params:this.getParams()
40815 success : function(response){
40816 var result = this.processResponse(response);
40817 if(result === true || !result.success || !result.data){
40818 this.failureType = Roo.form.Action.LOAD_FAILURE;
40819 this.form.afterAction(this, false);
40822 this.form.clearInvalid();
40823 this.form.setValues(result.data);
40824 this.form.afterAction(this, true);
40827 handleResponse : function(response){
40828 if(this.form.reader){
40829 var rs = this.form.reader.read(response);
40830 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
40832 success : rs.success,
40836 return Roo.decode(response.responseText);
40840 Roo.form.Action.ACTION_TYPES = {
40841 'load' : Roo.form.Action.Load,
40842 'submit' : Roo.form.Action.Submit
40845 * Ext JS Library 1.1.1
40846 * Copyright(c) 2006-2007, Ext JS, LLC.
40848 * Originally Released Under LGPL - original licence link has changed is not relivant.
40851 * <script type="text/javascript">
40855 * @class Roo.form.Layout
40856 * @extends Roo.Component
40857 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
40859 * @param {Object} config Configuration options
40861 Roo.form.Layout = function(config){
40863 if (config.items) {
40864 xitems = config.items;
40865 delete config.items;
40867 Roo.form.Layout.superclass.constructor.call(this, config);
40869 Roo.each(xitems, this.addxtype, this);
40873 Roo.extend(Roo.form.Layout, Roo.Component, {
40875 * @cfg {String/Object} autoCreate
40876 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
40879 * @cfg {String/Object/Function} style
40880 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
40881 * a function which returns such a specification.
40884 * @cfg {String} labelAlign
40885 * Valid values are "left," "top" and "right" (defaults to "left")
40888 * @cfg {Number} labelWidth
40889 * Fixed width in pixels of all field labels (defaults to undefined)
40892 * @cfg {Boolean} clear
40893 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
40897 * @cfg {String} labelSeparator
40898 * The separator to use after field labels (defaults to ':')
40900 labelSeparator : ':',
40902 * @cfg {Boolean} hideLabels
40903 * True to suppress the display of field labels in this layout (defaults to false)
40905 hideLabels : false,
40908 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
40913 onRender : function(ct, position){
40914 if(this.el){ // from markup
40915 this.el = Roo.get(this.el);
40916 }else { // generate
40917 var cfg = this.getAutoCreate();
40918 this.el = ct.createChild(cfg, position);
40921 this.el.applyStyles(this.style);
40923 if(this.labelAlign){
40924 this.el.addClass('x-form-label-'+this.labelAlign);
40926 if(this.hideLabels){
40927 this.labelStyle = "display:none";
40928 this.elementStyle = "padding-left:0;";
40930 if(typeof this.labelWidth == 'number'){
40931 this.labelStyle = "width:"+this.labelWidth+"px;";
40932 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
40934 if(this.labelAlign == 'top'){
40935 this.labelStyle = "width:auto;";
40936 this.elementStyle = "padding-left:0;";
40939 var stack = this.stack;
40940 var slen = stack.length;
40942 if(!this.fieldTpl){
40943 var t = new Roo.Template(
40944 '<div class="x-form-item {5}">',
40945 '<label for="{0}" style="{2}">{1}{4}</label>',
40946 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40948 '</div><div class="x-form-clear-left"></div>'
40950 t.disableFormats = true;
40952 Roo.form.Layout.prototype.fieldTpl = t;
40954 for(var i = 0; i < slen; i++) {
40955 if(stack[i].isFormField){
40956 this.renderField(stack[i]);
40958 this.renderComponent(stack[i]);
40963 this.el.createChild({cls:'x-form-clear'});
40968 renderField : function(f){
40969 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
40972 f.labelStyle||this.labelStyle||'', //2
40973 this.elementStyle||'', //3
40974 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
40975 f.itemCls||this.itemCls||'' //5
40976 ], true).getPrevSibling());
40980 renderComponent : function(c){
40981 c.render(c.isLayout ? this.el : this.el.createChild());
40984 * Adds a object form elements (using the xtype property as the factory method.)
40985 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
40986 * @param {Object} config
40988 addxtype : function(o)
40990 // create the lement.
40991 o.form = this.form;
40992 var fe = Roo.factory(o, Roo.form);
40993 this.form.allItems.push(fe);
40994 this.stack.push(fe);
40996 if (fe.isFormField) {
40997 this.form.items.add(fe);
41005 * @class Roo.form.Column
41006 * @extends Roo.form.Layout
41007 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41009 * @param {Object} config Configuration options
41011 Roo.form.Column = function(config){
41012 Roo.form.Column.superclass.constructor.call(this, config);
41015 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41017 * @cfg {Number/String} width
41018 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41021 * @cfg {String/Object} autoCreate
41022 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41026 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41029 onRender : function(ct, position){
41030 Roo.form.Column.superclass.onRender.call(this, ct, position);
41032 this.el.setWidth(this.width);
41039 * @class Roo.form.Row
41040 * @extends Roo.form.Layout
41041 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41043 * @param {Object} config Configuration options
41047 Roo.form.Row = function(config){
41048 Roo.form.Row.superclass.constructor.call(this, config);
41051 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41053 * @cfg {Number/String} width
41054 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41057 * @cfg {Number/String} height
41058 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41060 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41064 onRender : function(ct, position){
41065 //console.log('row render');
41067 var t = new Roo.Template(
41068 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41069 '<label for="{0}" style="{2}">{1}{4}</label>',
41070 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41074 t.disableFormats = true;
41076 Roo.form.Layout.prototype.rowTpl = t;
41078 this.fieldTpl = this.rowTpl;
41080 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41081 var labelWidth = 100;
41083 if ((this.labelAlign != 'top')) {
41084 if (typeof this.labelWidth == 'number') {
41085 labelWidth = this.labelWidth
41087 this.padWidth = 20 + labelWidth;
41091 Roo.form.Column.superclass.onRender.call(this, ct, position);
41093 this.el.setWidth(this.width);
41096 this.el.setHeight(this.height);
41101 renderField : function(f){
41102 f.fieldEl = this.fieldTpl.append(this.el, [
41103 f.id, f.fieldLabel,
41104 f.labelStyle||this.labelStyle||'',
41105 this.elementStyle||'',
41106 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41107 f.itemCls||this.itemCls||'',
41108 f.width ? f.width + this.padWidth : 160 + this.padWidth
41115 * @class Roo.form.FieldSet
41116 * @extends Roo.form.Layout
41117 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41119 * @param {Object} config Configuration options
41121 Roo.form.FieldSet = function(config){
41122 Roo.form.FieldSet.superclass.constructor.call(this, config);
41125 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41127 * @cfg {String} legend
41128 * The text to display as the legend for the FieldSet (defaults to '')
41131 * @cfg {String/Object} autoCreate
41132 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41136 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41139 onRender : function(ct, position){
41140 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
41142 this.setLegend(this.legend);
41147 setLegend : function(text){
41149 this.el.child('legend').update(text);
41154 * Ext JS Library 1.1.1
41155 * Copyright(c) 2006-2007, Ext JS, LLC.
41157 * Originally Released Under LGPL - original licence link has changed is not relivant.
41160 * <script type="text/javascript">
41163 * @class Roo.form.VTypes
41164 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41167 Roo.form.VTypes = function(){
41168 // closure these in so they are only created once.
41169 var alpha = /^[a-zA-Z_]+$/;
41170 var alphanum = /^[a-zA-Z0-9_]+$/;
41171 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41172 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41174 // All these messages and functions are configurable
41177 * The function used to validate email addresses
41178 * @param {String} value The email address
41180 'email' : function(v){
41181 return email.test(v);
41184 * The error text to display when the email validation function returns false
41187 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41189 * The keystroke filter mask to be applied on email input
41192 'emailMask' : /[a-z0-9_\.\-@]/i,
41195 * The function used to validate URLs
41196 * @param {String} value The URL
41198 'url' : function(v){
41199 return url.test(v);
41202 * The error text to display when the url validation function returns false
41205 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41208 * The function used to validate alpha values
41209 * @param {String} value The value
41211 'alpha' : function(v){
41212 return alpha.test(v);
41215 * The error text to display when the alpha validation function returns false
41218 'alphaText' : 'This field should only contain letters and _',
41220 * The keystroke filter mask to be applied on alpha input
41223 'alphaMask' : /[a-z_]/i,
41226 * The function used to validate alphanumeric values
41227 * @param {String} value The value
41229 'alphanum' : function(v){
41230 return alphanum.test(v);
41233 * The error text to display when the alphanumeric validation function returns false
41236 'alphanumText' : 'This field should only contain letters, numbers and _',
41238 * The keystroke filter mask to be applied on alphanumeric input
41241 'alphanumMask' : /[a-z0-9_]/i
41243 }();//<script type="text/javascript">
41246 * @class Roo.form.FCKeditor
41247 * @extends Roo.form.TextArea
41248 * Wrapper around the FCKEditor http://www.fckeditor.net
41250 * Creates a new FCKeditor
41251 * @param {Object} config Configuration options
41253 Roo.form.FCKeditor = function(config){
41254 Roo.form.FCKeditor.superclass.constructor.call(this, config);
41257 * @event editorinit
41258 * Fired when the editor is initialized - you can add extra handlers here..
41259 * @param {FCKeditor} this
41260 * @param {Object} the FCK object.
41267 Roo.form.FCKeditor.editors = { };
41268 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
41270 //defaultAutoCreate : {
41271 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
41275 * @cfg {Object} fck options - see fck manual for details.
41280 * @cfg {Object} fck toolbar set (Basic or Default)
41282 toolbarSet : 'Basic',
41284 * @cfg {Object} fck BasePath
41286 basePath : '/fckeditor/',
41294 onRender : function(ct, position)
41297 this.defaultAutoCreate = {
41299 style:"width:300px;height:60px;",
41300 autocomplete: "off"
41303 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
41306 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
41307 if(this.preventScrollbars){
41308 this.el.setStyle("overflow", "hidden");
41310 this.el.setHeight(this.growMin);
41313 //console.log('onrender' + this.getId() );
41314 Roo.form.FCKeditor.editors[this.getId()] = this;
41317 this.replaceTextarea() ;
41321 getEditor : function() {
41322 return this.fckEditor;
41325 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
41326 * @param {Mixed} value The value to set
41330 setValue : function(value)
41332 //console.log('setValue: ' + value);
41334 if(typeof(value) == 'undefined') { // not sure why this is happending...
41337 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41339 //if(!this.el || !this.getEditor()) {
41340 // this.value = value;
41341 //this.setValue.defer(100,this,[value]);
41345 if(!this.getEditor()) {
41349 this.getEditor().SetData(value);
41356 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
41357 * @return {Mixed} value The field value
41359 getValue : function()
41362 if (this.frame && this.frame.dom.style.display == 'none') {
41363 return Roo.form.FCKeditor.superclass.getValue.call(this);
41366 if(!this.el || !this.getEditor()) {
41368 // this.getValue.defer(100,this);
41373 var value=this.getEditor().GetData();
41374 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41375 return Roo.form.FCKeditor.superclass.getValue.call(this);
41381 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
41382 * @return {Mixed} value The field value
41384 getRawValue : function()
41386 if (this.frame && this.frame.dom.style.display == 'none') {
41387 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41390 if(!this.el || !this.getEditor()) {
41391 //this.getRawValue.defer(100,this);
41398 var value=this.getEditor().GetData();
41399 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
41400 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41404 setSize : function(w,h) {
41408 //if (this.frame && this.frame.dom.style.display == 'none') {
41409 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41412 //if(!this.el || !this.getEditor()) {
41413 // this.setSize.defer(100,this, [w,h]);
41419 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41421 this.frame.dom.setAttribute('width', w);
41422 this.frame.dom.setAttribute('height', h);
41423 this.frame.setSize(w,h);
41427 toggleSourceEdit : function(value) {
41431 this.el.dom.style.display = value ? '' : 'none';
41432 this.frame.dom.style.display = value ? 'none' : '';
41437 focus: function(tag)
41439 if (this.frame.dom.style.display == 'none') {
41440 return Roo.form.FCKeditor.superclass.focus.call(this);
41442 if(!this.el || !this.getEditor()) {
41443 this.focus.defer(100,this, [tag]);
41450 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
41451 this.getEditor().Focus();
41453 if (!this.getEditor().Selection.GetSelection()) {
41454 this.focus.defer(100,this, [tag]);
41459 var r = this.getEditor().EditorDocument.createRange();
41460 r.setStart(tgs[0],0);
41461 r.setEnd(tgs[0],0);
41462 this.getEditor().Selection.GetSelection().removeAllRanges();
41463 this.getEditor().Selection.GetSelection().addRange(r);
41464 this.getEditor().Focus();
41471 replaceTextarea : function()
41473 if ( document.getElementById( this.getId() + '___Frame' ) )
41475 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
41477 // We must check the elements firstly using the Id and then the name.
41478 var oTextarea = document.getElementById( this.getId() );
41480 var colElementsByName = document.getElementsByName( this.getId() ) ;
41482 oTextarea.style.display = 'none' ;
41484 if ( oTextarea.tabIndex ) {
41485 this.TabIndex = oTextarea.tabIndex ;
41488 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
41489 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
41490 this.frame = Roo.get(this.getId() + '___Frame')
41493 _getConfigHtml : function()
41497 for ( var o in this.fckconfig ) {
41498 sConfig += sConfig.length > 0 ? '&' : '';
41499 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
41502 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
41506 _getIFrameHtml : function()
41508 var sFile = 'fckeditor.html' ;
41509 /* no idea what this is about..
41512 if ( (/fcksource=true/i).test( window.top.location.search ) )
41513 sFile = 'fckeditor.original.html' ;
41518 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
41519 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
41522 var html = '<iframe id="' + this.getId() +
41523 '___Frame" src="' + sLink +
41524 '" width="' + this.width +
41525 '" height="' + this.height + '"' +
41526 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
41527 ' frameborder="0" scrolling="no"></iframe>' ;
41532 _insertHtmlBefore : function( html, element )
41534 if ( element.insertAdjacentHTML ) {
41536 element.insertAdjacentHTML( 'beforeBegin', html ) ;
41538 var oRange = document.createRange() ;
41539 oRange.setStartBefore( element ) ;
41540 var oFragment = oRange.createContextualFragment( html );
41541 element.parentNode.insertBefore( oFragment, element ) ;
41554 //Roo.reg('fckeditor', Roo.form.FCKeditor);
41556 function FCKeditor_OnComplete(editorInstance){
41557 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
41558 f.fckEditor = editorInstance;
41559 //console.log("loaded");
41560 f.fireEvent('editorinit', f, editorInstance);
41580 //<script type="text/javascript">
41582 * @class Roo.form.GridField
41583 * @extends Roo.form.Field
41584 * Embed a grid (or editable grid into a form)
41587 * Creates a new GridField
41588 * @param {Object} config Configuration options
41590 Roo.form.GridField = function(config){
41591 Roo.form.GridField.superclass.constructor.call(this, config);
41595 Roo.extend(Roo.form.GridField, Roo.form.Field, {
41597 * @cfg {Number} width - used to restrict width of grid..
41601 * @cfg {Number} height - used to restrict height of grid..
41605 * @cfg {Object} xgrid (xtype'd description of grid) Grid or EditorGrid
41609 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41610 * {tag: "input", type: "checkbox", autocomplete: "off"})
41612 // defaultAutoCreate : { tag: 'div' },
41613 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
41615 * @cfg {String} addTitle Text to include for adding a title.
41619 onResize : function(){
41620 Roo.form.Field.superclass.onResize.apply(this, arguments);
41623 initEvents : function(){
41624 // Roo.form.Checkbox.superclass.initEvents.call(this);
41625 // has no events...
41630 getResizeEl : function(){
41634 getPositionEl : function(){
41639 onRender : function(ct, position){
41641 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
41642 var style = this.style;
41645 Roo.form.DisplayImage.superclass.onRender.call(this, ct, position);
41646 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
41647 this.viewEl = this.wrap.createChild({ tag: 'div' });
41649 this.viewEl.applyStyles(style);
41652 this.viewEl.setWidth(this.width);
41655 this.viewEl.setHeight(this.height);
41657 //if(this.inputValue !== undefined){
41658 //this.setValue(this.value);
41661 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
41664 this.grid.render();
41665 this.grid.getDataSource().on('remove', this.refreshValue, this);
41666 this.grid.getDataSource().on('update', this.refreshValue, this);
41667 this.grid.on('afteredit', this.refreshValue, this);
41673 * Sets the value of the item.
41674 * @param {String} either an object or a string..
41676 setValue : function(v){
41678 v = v || []; // empty set..
41679 // this does not seem smart - it really only affects memoryproxy grids..
41680 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
41681 var ds = this.grid.getDataSource();
41682 // assumes a json reader..
41684 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
41685 ds.loadData( data);
41687 Roo.form.GridField.superclass.setValue.call(this, v);
41688 this.refreshValue();
41689 // should load data in the grid really....
41693 refreshValue: function() {
41695 this.grid.getDataSource().each(function(r) {
41698 this.el.dom.value = Roo.encode(val);
41704 });//<script type="text/javasscript">
41708 * @class Roo.DDView
41709 * A DnD enabled version of Roo.View.
41710 * @param {Element/String} container The Element in which to create the View.
41711 * @param {String} tpl The template string used to create the markup for each element of the View
41712 * @param {Object} config The configuration properties. These include all the config options of
41713 * {@link Roo.View} plus some specific to this class.<br>
41715 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
41716 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
41718 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
41719 .x-view-drag-insert-above {
41720 border-top:1px dotted #3366cc;
41722 .x-view-drag-insert-below {
41723 border-bottom:1px dotted #3366cc;
41729 Roo.DDView = function(container, tpl, config) {
41730 Roo.DDView.superclass.constructor.apply(this, arguments);
41731 this.getEl().setStyle("outline", "0px none");
41732 this.getEl().unselectable();
41733 if (this.dragGroup) {
41734 this.setDraggable(this.dragGroup.split(","));
41736 if (this.dropGroup) {
41737 this.setDroppable(this.dropGroup.split(","));
41739 if (this.deletable) {
41740 this.setDeletable();
41742 this.isDirtyFlag = false;
41748 Roo.extend(Roo.DDView, Roo.View, {
41749 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
41750 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
41751 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
41752 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
41756 reset: Roo.emptyFn,
41758 clearInvalid: Roo.form.Field.prototype.clearInvalid,
41760 validate: function() {
41764 destroy: function() {
41765 this.purgeListeners();
41766 this.getEl.removeAllListeners();
41767 this.getEl().remove();
41768 if (this.dragZone) {
41769 if (this.dragZone.destroy) {
41770 this.dragZone.destroy();
41773 if (this.dropZone) {
41774 if (this.dropZone.destroy) {
41775 this.dropZone.destroy();
41780 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
41781 getName: function() {
41785 /** Loads the View from a JSON string representing the Records to put into the Store. */
41786 setValue: function(v) {
41788 throw "DDView.setValue(). DDView must be constructed with a valid Store";
41791 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
41792 this.store.proxy = new Roo.data.MemoryProxy(data);
41796 /** @return {String} a parenthesised list of the ids of the Records in the View. */
41797 getValue: function() {
41799 this.store.each(function(rec) {
41800 result += rec.id + ',';
41802 return result.substr(0, result.length - 1) + ')';
41805 getIds: function() {
41806 var i = 0, result = new Array(this.store.getCount());
41807 this.store.each(function(rec) {
41808 result[i++] = rec.id;
41813 isDirty: function() {
41814 return this.isDirtyFlag;
41818 * Part of the Roo.dd.DropZone interface. If no target node is found, the
41819 * whole Element becomes the target, and this causes the drop gesture to append.
41821 getTargetFromEvent : function(e) {
41822 var target = e.getTarget();
41823 while ((target !== null) && (target.parentNode != this.el.dom)) {
41824 target = target.parentNode;
41827 target = this.el.dom.lastChild || this.el.dom;
41833 * Create the drag data which consists of an object which has the property "ddel" as
41834 * the drag proxy element.
41836 getDragData : function(e) {
41837 var target = this.findItemFromChild(e.getTarget());
41839 this.handleSelection(e);
41840 var selNodes = this.getSelectedNodes();
41843 copy: this.copy || (this.allowCopy && e.ctrlKey),
41847 var selectedIndices = this.getSelectedIndexes();
41848 for (var i = 0; i < selectedIndices.length; i++) {
41849 dragData.records.push(this.store.getAt(selectedIndices[i]));
41851 if (selNodes.length == 1) {
41852 dragData.ddel = target.cloneNode(true); // the div element
41854 var div = document.createElement('div'); // create the multi element drag "ghost"
41855 div.className = 'multi-proxy';
41856 for (var i = 0, len = selNodes.length; i < len; i++) {
41857 div.appendChild(selNodes[i].cloneNode(true));
41859 dragData.ddel = div;
41861 //console.log(dragData)
41862 //console.log(dragData.ddel.innerHTML)
41865 //console.log('nodragData')
41869 /** Specify to which ddGroup items in this DDView may be dragged. */
41870 setDraggable: function(ddGroup) {
41871 if (ddGroup instanceof Array) {
41872 Roo.each(ddGroup, this.setDraggable, this);
41875 if (this.dragZone) {
41876 this.dragZone.addToGroup(ddGroup);
41878 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
41879 containerScroll: true,
41883 // Draggability implies selection. DragZone's mousedown selects the element.
41884 if (!this.multiSelect) { this.singleSelect = true; }
41886 // Wire the DragZone's handlers up to methods in *this*
41887 this.dragZone.getDragData = this.getDragData.createDelegate(this);
41891 /** Specify from which ddGroup this DDView accepts drops. */
41892 setDroppable: function(ddGroup) {
41893 if (ddGroup instanceof Array) {
41894 Roo.each(ddGroup, this.setDroppable, this);
41897 if (this.dropZone) {
41898 this.dropZone.addToGroup(ddGroup);
41900 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
41901 containerScroll: true,
41905 // Wire the DropZone's handlers up to methods in *this*
41906 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
41907 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
41908 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
41909 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
41910 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
41914 /** Decide whether to drop above or below a View node. */
41915 getDropPoint : function(e, n, dd){
41916 if (n == this.el.dom) { return "above"; }
41917 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
41918 var c = t + (b - t) / 2;
41919 var y = Roo.lib.Event.getPageY(e);
41927 onNodeEnter : function(n, dd, e, data){
41931 onNodeOver : function(n, dd, e, data){
41932 var pt = this.getDropPoint(e, n, dd);
41933 // set the insert point style on the target node
41934 var dragElClass = this.dropNotAllowed;
41937 if (pt == "above"){
41938 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
41939 targetElClass = "x-view-drag-insert-above";
41941 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
41942 targetElClass = "x-view-drag-insert-below";
41944 if (this.lastInsertClass != targetElClass){
41945 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
41946 this.lastInsertClass = targetElClass;
41949 return dragElClass;
41952 onNodeOut : function(n, dd, e, data){
41953 this.removeDropIndicators(n);
41956 onNodeDrop : function(n, dd, e, data){
41957 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
41960 var pt = this.getDropPoint(e, n, dd);
41961 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
41962 if (pt == "below") { insertAt++; }
41963 for (var i = 0; i < data.records.length; i++) {
41964 var r = data.records[i];
41965 var dup = this.store.getById(r.id);
41966 if (dup && (dd != this.dragZone)) {
41967 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
41970 this.store.insert(insertAt++, r.copy());
41972 data.source.isDirtyFlag = true;
41974 this.store.insert(insertAt++, r);
41976 this.isDirtyFlag = true;
41979 this.dragZone.cachedTarget = null;
41983 removeDropIndicators : function(n){
41985 Roo.fly(n).removeClass([
41986 "x-view-drag-insert-above",
41987 "x-view-drag-insert-below"]);
41988 this.lastInsertClass = "_noclass";
41993 * Utility method. Add a delete option to the DDView's context menu.
41994 * @param {String} imageUrl The URL of the "delete" icon image.
41996 setDeletable: function(imageUrl) {
41997 if (!this.singleSelect && !this.multiSelect) {
41998 this.singleSelect = true;
42000 var c = this.getContextMenu();
42001 this.contextMenu.on("itemclick", function(item) {
42004 this.remove(this.getSelectedIndexes());
42008 this.contextMenu.add({
42015 /** Return the context menu for this DDView. */
42016 getContextMenu: function() {
42017 if (!this.contextMenu) {
42018 // Create the View's context menu
42019 this.contextMenu = new Roo.menu.Menu({
42020 id: this.id + "-contextmenu"
42022 this.el.on("contextmenu", this.showContextMenu, this);
42024 return this.contextMenu;
42027 disableContextMenu: function() {
42028 if (this.contextMenu) {
42029 this.el.un("contextmenu", this.showContextMenu, this);
42033 showContextMenu: function(e, item) {
42034 item = this.findItemFromChild(e.getTarget());
42037 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
42038 this.contextMenu.showAt(e.getXY());
42043 * Remove {@link Roo.data.Record}s at the specified indices.
42044 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42046 remove: function(selectedIndices) {
42047 selectedIndices = [].concat(selectedIndices);
42048 for (var i = 0; i < selectedIndices.length; i++) {
42049 var rec = this.store.getAt(selectedIndices[i]);
42050 this.store.remove(rec);
42055 * Double click fires the event, but also, if this is draggable, and there is only one other
42056 * related DropZone, it transfers the selected node.
42058 onDblClick : function(e){
42059 var item = this.findItemFromChild(e.getTarget());
42061 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
42064 if (this.dragGroup) {
42065 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
42066 while (targets.indexOf(this.dropZone) > -1) {
42067 targets.remove(this.dropZone);
42069 if (targets.length == 1) {
42070 this.dragZone.cachedTarget = null;
42071 var el = Roo.get(targets[0].getEl());
42072 var box = el.getBox(true);
42073 targets[0].onNodeDrop(el.dom, {
42075 xy: [box.x, box.y + box.height - 1]
42076 }, null, this.getDragData(e));
42082 handleSelection: function(e) {
42083 this.dragZone.cachedTarget = null;
42084 var item = this.findItemFromChild(e.getTarget());
42086 this.clearSelections(true);
42089 if (item && (this.multiSelect || this.singleSelect)){
42090 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
42091 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
42092 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
42093 this.unselect(item);
42095 this.select(item, this.multiSelect && e.ctrlKey);
42096 this.lastSelection = item;
42101 onItemClick : function(item, index, e){
42102 if(this.fireEvent("beforeclick", this, index, item, e) === false){
42108 unselect : function(nodeInfo, suppressEvent){
42109 var node = this.getNode(nodeInfo);
42110 if(node && this.isSelected(node)){
42111 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
42112 Roo.fly(node).removeClass(this.selectedClass);
42113 this.selections.remove(node);
42114 if(!suppressEvent){
42115 this.fireEvent("selectionchange", this, this.selections);
42123 * Ext JS Library 1.1.1
42124 * Copyright(c) 2006-2007, Ext JS, LLC.
42126 * Originally Released Under LGPL - original licence link has changed is not relivant.
42129 * <script type="text/javascript">
42133 * @class Roo.LayoutManager
42134 * @extends Roo.util.Observable
42135 * Base class for layout managers.
42137 Roo.LayoutManager = function(container, config){
42138 Roo.LayoutManager.superclass.constructor.call(this);
42139 this.el = Roo.get(container);
42140 // ie scrollbar fix
42141 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
42142 document.body.scroll = "no";
42143 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
42144 this.el.position('relative');
42146 this.id = this.el.id;
42147 this.el.addClass("x-layout-container");
42148 /** false to disable window resize monitoring @type Boolean */
42149 this.monitorWindowResize = true;
42154 * Fires when a layout is performed.
42155 * @param {Roo.LayoutManager} this
42159 * @event regionresized
42160 * Fires when the user resizes a region.
42161 * @param {Roo.LayoutRegion} region The resized region
42162 * @param {Number} newSize The new size (width for east/west, height for north/south)
42164 "regionresized" : true,
42166 * @event regioncollapsed
42167 * Fires when a region is collapsed.
42168 * @param {Roo.LayoutRegion} region The collapsed region
42170 "regioncollapsed" : true,
42172 * @event regionexpanded
42173 * Fires when a region is expanded.
42174 * @param {Roo.LayoutRegion} region The expanded region
42176 "regionexpanded" : true
42178 this.updating = false;
42179 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
42182 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
42184 * Returns true if this layout is currently being updated
42185 * @return {Boolean}
42187 isUpdating : function(){
42188 return this.updating;
42192 * Suspend the LayoutManager from doing auto-layouts while
42193 * making multiple add or remove calls
42195 beginUpdate : function(){
42196 this.updating = true;
42200 * Restore auto-layouts and optionally disable the manager from performing a layout
42201 * @param {Boolean} noLayout true to disable a layout update
42203 endUpdate : function(noLayout){
42204 this.updating = false;
42210 layout: function(){
42214 onRegionResized : function(region, newSize){
42215 this.fireEvent("regionresized", region, newSize);
42219 onRegionCollapsed : function(region){
42220 this.fireEvent("regioncollapsed", region);
42223 onRegionExpanded : function(region){
42224 this.fireEvent("regionexpanded", region);
42228 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
42229 * performs box-model adjustments.
42230 * @return {Object} The size as an object {width: (the width), height: (the height)}
42232 getViewSize : function(){
42234 if(this.el.dom != document.body){
42235 size = this.el.getSize();
42237 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
42239 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
42240 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
42245 * Returns the Element this layout is bound to.
42246 * @return {Roo.Element}
42248 getEl : function(){
42253 * Returns the specified region.
42254 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
42255 * @return {Roo.LayoutRegion}
42257 getRegion : function(target){
42258 return this.regions[target.toLowerCase()];
42261 onWindowResize : function(){
42262 if(this.monitorWindowResize){
42268 * Ext JS Library 1.1.1
42269 * Copyright(c) 2006-2007, Ext JS, LLC.
42271 * Originally Released Under LGPL - original licence link has changed is not relivant.
42274 * <script type="text/javascript">
42277 * @class Roo.BorderLayout
42278 * @extends Roo.LayoutManager
42279 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
42280 * please see: <br><br>
42281 * <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>
42282 * <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>
42285 var layout = new Roo.BorderLayout(document.body, {
42319 preferredTabWidth: 150
42324 var CP = Roo.ContentPanel;
42326 layout.beginUpdate();
42327 layout.add("north", new CP("north", "North"));
42328 layout.add("south", new CP("south", {title: "South", closable: true}));
42329 layout.add("west", new CP("west", {title: "West"}));
42330 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
42331 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
42332 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
42333 layout.getRegion("center").showPanel("center1");
42334 layout.endUpdate();
42337 <b>The container the layout is rendered into can be either the body element or any other element.
42338 If it is not the body element, the container needs to either be an absolute positioned element,
42339 or you will need to add "position:relative" to the css of the container. You will also need to specify
42340 the container size if it is not the body element.</b>
42343 * Create a new BorderLayout
42344 * @param {String/HTMLElement/Element} container The container this layout is bound to
42345 * @param {Object} config Configuration options
42347 Roo.BorderLayout = function(container, config){
42348 config = config || {};
42349 Roo.BorderLayout.superclass.constructor.call(this, container, config);
42350 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
42351 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
42352 var target = this.factory.validRegions[i];
42353 if(config[target]){
42354 this.addRegion(target, config[target]);
42359 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
42361 * Creates and adds a new region if it doesn't already exist.
42362 * @param {String} target The target region key (north, south, east, west or center).
42363 * @param {Object} config The regions config object
42364 * @return {BorderLayoutRegion} The new region
42366 addRegion : function(target, config){
42367 if(!this.regions[target]){
42368 var r = this.factory.create(target, this, config);
42369 this.bindRegion(target, r);
42371 return this.regions[target];
42375 bindRegion : function(name, r){
42376 this.regions[name] = r;
42377 r.on("visibilitychange", this.layout, this);
42378 r.on("paneladded", this.layout, this);
42379 r.on("panelremoved", this.layout, this);
42380 r.on("invalidated", this.layout, this);
42381 r.on("resized", this.onRegionResized, this);
42382 r.on("collapsed", this.onRegionCollapsed, this);
42383 r.on("expanded", this.onRegionExpanded, this);
42387 * Performs a layout update.
42389 layout : function(){
42390 if(this.updating) return;
42391 var size = this.getViewSize();
42392 var w = size.width;
42393 var h = size.height;
42398 //var x = 0, y = 0;
42400 var rs = this.regions;
42401 var north = rs["north"];
42402 var south = rs["south"];
42403 var west = rs["west"];
42404 var east = rs["east"];
42405 var center = rs["center"];
42406 //if(this.hideOnLayout){ // not supported anymore
42407 //c.el.setStyle("display", "none");
42409 if(north && north.isVisible()){
42410 var b = north.getBox();
42411 var m = north.getMargins();
42412 b.width = w - (m.left+m.right);
42415 centerY = b.height + b.y + m.bottom;
42416 centerH -= centerY;
42417 north.updateBox(this.safeBox(b));
42419 if(south && south.isVisible()){
42420 var b = south.getBox();
42421 var m = south.getMargins();
42422 b.width = w - (m.left+m.right);
42424 var totalHeight = (b.height + m.top + m.bottom);
42425 b.y = h - totalHeight + m.top;
42426 centerH -= totalHeight;
42427 south.updateBox(this.safeBox(b));
42429 if(west && west.isVisible()){
42430 var b = west.getBox();
42431 var m = west.getMargins();
42432 b.height = centerH - (m.top+m.bottom);
42434 b.y = centerY + m.top;
42435 var totalWidth = (b.width + m.left + m.right);
42436 centerX += totalWidth;
42437 centerW -= totalWidth;
42438 west.updateBox(this.safeBox(b));
42440 if(east && east.isVisible()){
42441 var b = east.getBox();
42442 var m = east.getMargins();
42443 b.height = centerH - (m.top+m.bottom);
42444 var totalWidth = (b.width + m.left + m.right);
42445 b.x = w - totalWidth + m.left;
42446 b.y = centerY + m.top;
42447 centerW -= totalWidth;
42448 east.updateBox(this.safeBox(b));
42451 var m = center.getMargins();
42453 x: centerX + m.left,
42454 y: centerY + m.top,
42455 width: centerW - (m.left+m.right),
42456 height: centerH - (m.top+m.bottom)
42458 //if(this.hideOnLayout){
42459 //center.el.setStyle("display", "block");
42461 center.updateBox(this.safeBox(centerBox));
42464 this.fireEvent("layout", this);
42468 safeBox : function(box){
42469 box.width = Math.max(0, box.width);
42470 box.height = Math.max(0, box.height);
42475 * Adds a ContentPanel (or subclass) to this layout.
42476 * @param {String} target The target region key (north, south, east, west or center).
42477 * @param {Roo.ContentPanel} panel The panel to add
42478 * @return {Roo.ContentPanel} The added panel
42480 add : function(target, panel){
42482 target = target.toLowerCase();
42483 return this.regions[target].add(panel);
42487 * Remove a ContentPanel (or subclass) to this layout.
42488 * @param {String} target The target region key (north, south, east, west or center).
42489 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
42490 * @return {Roo.ContentPanel} The removed panel
42492 remove : function(target, panel){
42493 target = target.toLowerCase();
42494 return this.regions[target].remove(panel);
42498 * Searches all regions for a panel with the specified id
42499 * @param {String} panelId
42500 * @return {Roo.ContentPanel} The panel or null if it wasn't found
42502 findPanel : function(panelId){
42503 var rs = this.regions;
42504 for(var target in rs){
42505 if(typeof rs[target] != "function"){
42506 var p = rs[target].getPanel(panelId);
42516 * Searches all regions for a panel with the specified id and activates (shows) it.
42517 * @param {String/ContentPanel} panelId The panels id or the panel itself
42518 * @return {Roo.ContentPanel} The shown panel or null
42520 showPanel : function(panelId) {
42521 var rs = this.regions;
42522 for(var target in rs){
42523 var r = rs[target];
42524 if(typeof r != "function"){
42525 if(r.hasPanel(panelId)){
42526 return r.showPanel(panelId);
42534 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
42535 * @param {Roo.state.Provider} provider (optional) An alternate state provider
42537 restoreState : function(provider){
42539 provider = Roo.state.Manager;
42541 var sm = new Roo.LayoutStateManager();
42542 sm.init(this, provider);
42546 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
42547 * object should contain properties for each region to add ContentPanels to, and each property's value should be
42548 * a valid ContentPanel config object. Example:
42550 // Create the main layout
42551 var layout = new Roo.BorderLayout('main-ct', {
42562 // Create and add multiple ContentPanels at once via configs
42565 id: 'source-files',
42567 title:'Ext Source Files',
42580 * @param {Object} regions An object containing ContentPanel configs by region name
42582 batchAdd : function(regions){
42583 this.beginUpdate();
42584 for(var rname in regions){
42585 var lr = this.regions[rname];
42587 this.addTypedPanels(lr, regions[rname]);
42594 addTypedPanels : function(lr, ps){
42595 if(typeof ps == 'string'){
42596 lr.add(new Roo.ContentPanel(ps));
42598 else if(ps instanceof Array){
42599 for(var i =0, len = ps.length; i < len; i++){
42600 this.addTypedPanels(lr, ps[i]);
42603 else if(!ps.events){ // raw config?
42605 delete ps.el; // prevent conflict
42606 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
42608 else { // panel object assumed!
42613 * Adds a xtype elements to the layout.
42617 xtype : 'ContentPanel',
42624 xtype : 'NestedLayoutPanel',
42630 items : [ ... list of content panels or nested layout panels.. ]
42634 * @param {Object} cfg Xtype definition of item to add.
42636 addxtype : function(cfg)
42638 // basically accepts a pannel...
42639 // can accept a layout region..!?!?
42640 // console.log('BorderLayout add ' + cfg.xtype)
42642 if (!cfg.xtype.match(/Panel$/)) {
42646 var region = cfg.region;
42652 xitems = cfg.items;
42659 case 'ContentPanel': // ContentPanel (el, cfg)
42660 if(cfg.autoCreate) {
42661 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42663 var el = this.el.createChild();
42664 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
42667 this.add(region, ret);
42671 case 'TreePanel': // our new panel!
42672 cfg.el = this.el.createChild();
42673 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42674 this.add(region, ret);
42677 case 'NestedLayoutPanel':
42678 // create a new Layout (which is a Border Layout...
42679 var el = this.el.createChild();
42680 var clayout = cfg.layout;
42682 clayout.items = clayout.items || [];
42683 // replace this exitems with the clayout ones..
42684 xitems = clayout.items;
42687 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
42688 cfg.background = false;
42690 var layout = new Roo.BorderLayout(el, clayout);
42692 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
42693 //console.log('adding nested layout panel ' + cfg.toSource());
42694 this.add(region, ret);
42700 // needs grid and region
42702 //var el = this.getRegion(region).el.createChild();
42703 var el = this.el.createChild();
42704 // create the grid first...
42706 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
42708 if (region == 'center' && this.active ) {
42709 cfg.background = false;
42711 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
42713 this.add(region, ret);
42714 if (cfg.background) {
42715 ret.on('activate', function(gp) {
42716 if (!gp.grid.rendered) {
42729 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
42731 // GridPanel (grid, cfg)
42734 this.beginUpdate();
42736 Roo.each(xitems, function(i) {
42746 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
42747 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
42748 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
42749 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
42752 var CP = Roo.ContentPanel;
42754 var layout = Roo.BorderLayout.create({
42758 panels: [new CP("north", "North")]
42767 panels: [new CP("west", {title: "West"})]
42776 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
42785 panels: [new CP("south", {title: "South", closable: true})]
42792 preferredTabWidth: 150,
42794 new CP("center1", {title: "Close Me", closable: true}),
42795 new CP("center2", {title: "Center Panel", closable: false})
42800 layout.getRegion("center").showPanel("center1");
42805 Roo.BorderLayout.create = function(config, targetEl){
42806 var layout = new Roo.BorderLayout(targetEl || document.body, config);
42807 layout.beginUpdate();
42808 var regions = Roo.BorderLayout.RegionFactory.validRegions;
42809 for(var j = 0, jlen = regions.length; j < jlen; j++){
42810 var lr = regions[j];
42811 if(layout.regions[lr] && config[lr].panels){
42812 var r = layout.regions[lr];
42813 var ps = config[lr].panels;
42814 layout.addTypedPanels(r, ps);
42817 layout.endUpdate();
42822 Roo.BorderLayout.RegionFactory = {
42824 validRegions : ["north","south","east","west","center"],
42827 create : function(target, mgr, config){
42828 target = target.toLowerCase();
42829 if(config.lightweight || config.basic){
42830 return new Roo.BasicLayoutRegion(mgr, config, target);
42834 return new Roo.NorthLayoutRegion(mgr, config);
42836 return new Roo.SouthLayoutRegion(mgr, config);
42838 return new Roo.EastLayoutRegion(mgr, config);
42840 return new Roo.WestLayoutRegion(mgr, config);
42842 return new Roo.CenterLayoutRegion(mgr, config);
42844 throw 'Layout region "'+target+'" not supported.';
42848 * Ext JS Library 1.1.1
42849 * Copyright(c) 2006-2007, Ext JS, LLC.
42851 * Originally Released Under LGPL - original licence link has changed is not relivant.
42854 * <script type="text/javascript">
42858 * @class Roo.BasicLayoutRegion
42859 * @extends Roo.util.Observable
42860 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
42861 * and does not have a titlebar, tabs or any other features. All it does is size and position
42862 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
42864 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
42866 this.position = pos;
42869 * @scope Roo.BasicLayoutRegion
42873 * @event beforeremove
42874 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
42875 * @param {Roo.LayoutRegion} this
42876 * @param {Roo.ContentPanel} panel The panel
42877 * @param {Object} e The cancel event object
42879 "beforeremove" : true,
42881 * @event invalidated
42882 * Fires when the layout for this region is changed.
42883 * @param {Roo.LayoutRegion} this
42885 "invalidated" : true,
42887 * @event visibilitychange
42888 * Fires when this region is shown or hidden
42889 * @param {Roo.LayoutRegion} this
42890 * @param {Boolean} visibility true or false
42892 "visibilitychange" : true,
42894 * @event paneladded
42895 * Fires when a panel is added.
42896 * @param {Roo.LayoutRegion} this
42897 * @param {Roo.ContentPanel} panel The panel
42899 "paneladded" : true,
42901 * @event panelremoved
42902 * Fires when a panel is removed.
42903 * @param {Roo.LayoutRegion} this
42904 * @param {Roo.ContentPanel} panel The panel
42906 "panelremoved" : true,
42909 * Fires when this region is collapsed.
42910 * @param {Roo.LayoutRegion} this
42912 "collapsed" : true,
42915 * Fires when this region is expanded.
42916 * @param {Roo.LayoutRegion} this
42921 * Fires when this region is slid into view.
42922 * @param {Roo.LayoutRegion} this
42924 "slideshow" : true,
42927 * Fires when this region slides out of view.
42928 * @param {Roo.LayoutRegion} this
42930 "slidehide" : true,
42932 * @event panelactivated
42933 * Fires when a panel is activated.
42934 * @param {Roo.LayoutRegion} this
42935 * @param {Roo.ContentPanel} panel The activated panel
42937 "panelactivated" : true,
42940 * Fires when the user resizes this region.
42941 * @param {Roo.LayoutRegion} this
42942 * @param {Number} newSize The new size (width for east/west, height for north/south)
42946 /** A collection of panels in this region. @type Roo.util.MixedCollection */
42947 this.panels = new Roo.util.MixedCollection();
42948 this.panels.getKey = this.getPanelId.createDelegate(this);
42950 this.activePanel = null;
42951 // ensure listeners are added...
42953 if (config.listeners || config.events) {
42954 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
42955 listeners : config.listeners || {},
42956 events : config.events || {}
42960 if(skipConfig !== true){
42961 this.applyConfig(config);
42965 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
42966 getPanelId : function(p){
42970 applyConfig : function(config){
42971 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
42972 this.config = config;
42977 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
42978 * the width, for horizontal (north, south) the height.
42979 * @param {Number} newSize The new width or height
42981 resizeTo : function(newSize){
42982 var el = this.el ? this.el :
42983 (this.activePanel ? this.activePanel.getEl() : null);
42985 switch(this.position){
42988 el.setWidth(newSize);
42989 this.fireEvent("resized", this, newSize);
42993 el.setHeight(newSize);
42994 this.fireEvent("resized", this, newSize);
43000 getBox : function(){
43001 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
43004 getMargins : function(){
43005 return this.margins;
43008 updateBox : function(box){
43010 var el = this.activePanel.getEl();
43011 el.dom.style.left = box.x + "px";
43012 el.dom.style.top = box.y + "px";
43013 this.activePanel.setSize(box.width, box.height);
43017 * Returns the container element for this region.
43018 * @return {Roo.Element}
43020 getEl : function(){
43021 return this.activePanel;
43025 * Returns true if this region is currently visible.
43026 * @return {Boolean}
43028 isVisible : function(){
43029 return this.activePanel ? true : false;
43032 setActivePanel : function(panel){
43033 panel = this.getPanel(panel);
43034 if(this.activePanel && this.activePanel != panel){
43035 this.activePanel.setActiveState(false);
43036 this.activePanel.getEl().setLeftTop(-10000,-10000);
43038 this.activePanel = panel;
43039 panel.setActiveState(true);
43041 panel.setSize(this.box.width, this.box.height);
43043 this.fireEvent("panelactivated", this, panel);
43044 this.fireEvent("invalidated");
43048 * Show the specified panel.
43049 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43050 * @return {Roo.ContentPanel} The shown panel or null
43052 showPanel : function(panel){
43053 if(panel = this.getPanel(panel)){
43054 this.setActivePanel(panel);
43060 * Get the active panel for this region.
43061 * @return {Roo.ContentPanel} The active panel or null
43063 getActivePanel : function(){
43064 return this.activePanel;
43068 * Add the passed ContentPanel(s)
43069 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43070 * @return {Roo.ContentPanel} The panel added (if only one was added)
43072 add : function(panel){
43073 if(arguments.length > 1){
43074 for(var i = 0, len = arguments.length; i < len; i++) {
43075 this.add(arguments[i]);
43079 if(this.hasPanel(panel)){
43080 this.showPanel(panel);
43083 var el = panel.getEl();
43084 if(el.dom.parentNode != this.mgr.el.dom){
43085 this.mgr.el.dom.appendChild(el.dom);
43087 if(panel.setRegion){
43088 panel.setRegion(this);
43090 this.panels.add(panel);
43091 el.setStyle("position", "absolute");
43092 if(!panel.background){
43093 this.setActivePanel(panel);
43094 if(this.config.initialSize && this.panels.getCount()==1){
43095 this.resizeTo(this.config.initialSize);
43098 this.fireEvent("paneladded", this, panel);
43103 * Returns true if the panel is in this region.
43104 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43105 * @return {Boolean}
43107 hasPanel : function(panel){
43108 if(typeof panel == "object"){ // must be panel obj
43109 panel = panel.getId();
43111 return this.getPanel(panel) ? true : false;
43115 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43116 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43117 * @param {Boolean} preservePanel Overrides the config preservePanel option
43118 * @return {Roo.ContentPanel} The panel that was removed
43120 remove : function(panel, preservePanel){
43121 panel = this.getPanel(panel);
43126 this.fireEvent("beforeremove", this, panel, e);
43127 if(e.cancel === true){
43130 var panelId = panel.getId();
43131 this.panels.removeKey(panelId);
43136 * Returns the panel specified or null if it's not in this region.
43137 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43138 * @return {Roo.ContentPanel}
43140 getPanel : function(id){
43141 if(typeof id == "object"){ // must be panel obj
43144 return this.panels.get(id);
43148 * Returns this regions position (north/south/east/west/center).
43151 getPosition: function(){
43152 return this.position;
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">
43166 * @class Roo.LayoutRegion
43167 * @extends Roo.BasicLayoutRegion
43168 * This class represents a region in a layout manager.
43169 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
43170 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
43171 * @cfg {Boolean} floatable False to disable floating (defaults to true)
43172 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
43173 * @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})
43174 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
43175 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
43176 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
43177 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
43178 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
43179 * @cfg {String} title The title for the region (overrides panel titles)
43180 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
43181 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
43182 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
43183 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
43184 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
43185 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
43186 * the space available, similar to FireFox 1.5 tabs (defaults to false)
43187 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
43188 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
43189 * @cfg {Boolean} showPin True to show a pin button
43190 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
43191 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
43192 * @cfg {Boolean} disableTabTips True to disable tab tooltips
43193 * @cfg {Number} width For East/West panels
43194 * @cfg {Number} height For North/South panels
43195 * @cfg {Boolean} split To show the splitter
43197 Roo.LayoutRegion = function(mgr, config, pos){
43198 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
43199 var dh = Roo.DomHelper;
43200 /** This region's container element
43201 * @type Roo.Element */
43202 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
43203 /** This region's title element
43204 * @type Roo.Element */
43206 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
43207 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
43208 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
43210 this.titleEl.enableDisplayMode();
43211 /** This region's title text element
43212 * @type HTMLElement */
43213 this.titleTextEl = this.titleEl.dom.firstChild;
43214 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
43215 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
43216 this.closeBtn.enableDisplayMode();
43217 this.closeBtn.on("click", this.closeClicked, this);
43218 this.closeBtn.hide();
43220 this.createBody(config);
43221 this.visible = true;
43222 this.collapsed = false;
43224 if(config.hideWhenEmpty){
43226 this.on("paneladded", this.validateVisibility, this);
43227 this.on("panelremoved", this.validateVisibility, this);
43229 this.applyConfig(config);
43232 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
43234 createBody : function(){
43235 /** This region's body element
43236 * @type Roo.Element */
43237 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
43240 applyConfig : function(c){
43241 if(c.collapsible && this.position != "center" && !this.collapsedEl){
43242 var dh = Roo.DomHelper;
43243 if(c.titlebar !== false){
43244 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
43245 this.collapseBtn.on("click", this.collapse, this);
43246 this.collapseBtn.enableDisplayMode();
43248 if(c.showPin === true || this.showPin){
43249 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
43250 this.stickBtn.enableDisplayMode();
43251 this.stickBtn.on("click", this.expand, this);
43252 this.stickBtn.hide();
43255 /** This region's collapsed element
43256 * @type Roo.Element */
43257 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
43258 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
43260 if(c.floatable !== false){
43261 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
43262 this.collapsedEl.on("click", this.collapseClick, this);
43265 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
43266 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
43267 id: "message", unselectable: "on", style:{"float":"left"}});
43268 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
43270 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
43271 this.expandBtn.on("click", this.expand, this);
43273 if(this.collapseBtn){
43274 this.collapseBtn.setVisible(c.collapsible == true);
43276 this.cmargins = c.cmargins || this.cmargins ||
43277 (this.position == "west" || this.position == "east" ?
43278 {top: 0, left: 2, right:2, bottom: 0} :
43279 {top: 2, left: 0, right:0, bottom: 2});
43280 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43281 this.bottomTabs = c.tabPosition != "top";
43282 this.autoScroll = c.autoScroll || false;
43283 if(this.autoScroll){
43284 this.bodyEl.setStyle("overflow", "auto");
43286 this.bodyEl.setStyle("overflow", "hidden");
43288 //if(c.titlebar !== false){
43289 if((!c.titlebar && !c.title) || c.titlebar === false){
43290 this.titleEl.hide();
43292 this.titleEl.show();
43294 this.titleTextEl.innerHTML = c.title;
43298 this.duration = c.duration || .30;
43299 this.slideDuration = c.slideDuration || .45;
43302 this.collapse(true);
43309 * Returns true if this region is currently visible.
43310 * @return {Boolean}
43312 isVisible : function(){
43313 return this.visible;
43317 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
43318 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
43320 setCollapsedTitle : function(title){
43321 title = title || " ";
43322 if(this.collapsedTitleTextEl){
43323 this.collapsedTitleTextEl.innerHTML = title;
43327 getBox : function(){
43329 if(!this.collapsed){
43330 b = this.el.getBox(false, true);
43332 b = this.collapsedEl.getBox(false, true);
43337 getMargins : function(){
43338 return this.collapsed ? this.cmargins : this.margins;
43341 highlight : function(){
43342 this.el.addClass("x-layout-panel-dragover");
43345 unhighlight : function(){
43346 this.el.removeClass("x-layout-panel-dragover");
43349 updateBox : function(box){
43351 if(!this.collapsed){
43352 this.el.dom.style.left = box.x + "px";
43353 this.el.dom.style.top = box.y + "px";
43354 this.updateBody(box.width, box.height);
43356 this.collapsedEl.dom.style.left = box.x + "px";
43357 this.collapsedEl.dom.style.top = box.y + "px";
43358 this.collapsedEl.setSize(box.width, box.height);
43361 this.tabs.autoSizeTabs();
43365 updateBody : function(w, h){
43367 this.el.setWidth(w);
43368 w -= this.el.getBorderWidth("rl");
43369 if(this.config.adjustments){
43370 w += this.config.adjustments[0];
43374 this.el.setHeight(h);
43375 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
43376 h -= this.el.getBorderWidth("tb");
43377 if(this.config.adjustments){
43378 h += this.config.adjustments[1];
43380 this.bodyEl.setHeight(h);
43382 h = this.tabs.syncHeight(h);
43385 if(this.panelSize){
43386 w = w !== null ? w : this.panelSize.width;
43387 h = h !== null ? h : this.panelSize.height;
43389 if(this.activePanel){
43390 var el = this.activePanel.getEl();
43391 w = w !== null ? w : el.getWidth();
43392 h = h !== null ? h : el.getHeight();
43393 this.panelSize = {width: w, height: h};
43394 this.activePanel.setSize(w, h);
43396 if(Roo.isIE && this.tabs){
43397 this.tabs.el.repaint();
43402 * Returns the container element for this region.
43403 * @return {Roo.Element}
43405 getEl : function(){
43410 * Hides this region.
43413 if(!this.collapsed){
43414 this.el.dom.style.left = "-2000px";
43417 this.collapsedEl.dom.style.left = "-2000px";
43418 this.collapsedEl.hide();
43420 this.visible = false;
43421 this.fireEvent("visibilitychange", this, false);
43425 * Shows this region if it was previously hidden.
43428 if(!this.collapsed){
43431 this.collapsedEl.show();
43433 this.visible = true;
43434 this.fireEvent("visibilitychange", this, true);
43437 closeClicked : function(){
43438 if(this.activePanel){
43439 this.remove(this.activePanel);
43443 collapseClick : function(e){
43445 e.stopPropagation();
43448 e.stopPropagation();
43454 * Collapses this region.
43455 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
43457 collapse : function(skipAnim){
43458 if(this.collapsed) return;
43459 this.collapsed = true;
43461 this.split.el.hide();
43463 if(this.config.animate && skipAnim !== true){
43464 this.fireEvent("invalidated", this);
43465 this.animateCollapse();
43467 this.el.setLocation(-20000,-20000);
43469 this.collapsedEl.show();
43470 this.fireEvent("collapsed", this);
43471 this.fireEvent("invalidated", this);
43475 animateCollapse : function(){
43480 * Expands this region if it was previously collapsed.
43481 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
43482 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
43484 expand : function(e, skipAnim){
43485 if(e) e.stopPropagation();
43486 if(!this.collapsed || this.el.hasActiveFx()) return;
43488 this.afterSlideIn();
43491 this.collapsed = false;
43492 if(this.config.animate && skipAnim !== true){
43493 this.animateExpand();
43497 this.split.el.show();
43499 this.collapsedEl.setLocation(-2000,-2000);
43500 this.collapsedEl.hide();
43501 this.fireEvent("invalidated", this);
43502 this.fireEvent("expanded", this);
43506 animateExpand : function(){
43510 initTabs : function(){
43511 this.bodyEl.setStyle("overflow", "hidden");
43512 var ts = new Roo.TabPanel(this.bodyEl.dom, {
43513 tabPosition: this.bottomTabs ? 'bottom' : 'top',
43514 disableTooltips: this.config.disableTabTips
43516 if(this.config.hideTabs){
43517 ts.stripWrap.setDisplayed(false);
43520 ts.resizeTabs = this.config.resizeTabs === true;
43521 ts.minTabWidth = this.config.minTabWidth || 40;
43522 ts.maxTabWidth = this.config.maxTabWidth || 250;
43523 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
43524 ts.monitorResize = false;
43525 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43526 ts.bodyEl.addClass('x-layout-tabs-body');
43527 this.panels.each(this.initPanelAsTab, this);
43530 initPanelAsTab : function(panel){
43531 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
43532 this.config.closeOnTab && panel.isClosable());
43533 if(panel.tabTip !== undefined){
43534 ti.setTooltip(panel.tabTip);
43536 ti.on("activate", function(){
43537 this.setActivePanel(panel);
43539 if(this.config.closeOnTab){
43540 ti.on("beforeclose", function(t, e){
43542 this.remove(panel);
43548 updatePanelTitle : function(panel, title){
43549 if(this.activePanel == panel){
43550 this.updateTitle(title);
43553 var ti = this.tabs.getTab(panel.getEl().id);
43555 if(panel.tabTip !== undefined){
43556 ti.setTooltip(panel.tabTip);
43561 updateTitle : function(title){
43562 if(this.titleTextEl && !this.config.title){
43563 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
43567 setActivePanel : function(panel){
43568 panel = this.getPanel(panel);
43569 if(this.activePanel && this.activePanel != panel){
43570 this.activePanel.setActiveState(false);
43572 this.activePanel = panel;
43573 panel.setActiveState(true);
43574 if(this.panelSize){
43575 panel.setSize(this.panelSize.width, this.panelSize.height);
43578 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
43580 this.updateTitle(panel.getTitle());
43582 this.fireEvent("invalidated", this);
43584 this.fireEvent("panelactivated", this, panel);
43588 * Shows the specified panel.
43589 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
43590 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
43592 showPanel : function(panel){
43593 if(panel = this.getPanel(panel)){
43595 var tab = this.tabs.getTab(panel.getEl().id);
43596 if(tab.isHidden()){
43597 this.tabs.unhideTab(tab.id);
43601 this.setActivePanel(panel);
43608 * Get the active panel for this region.
43609 * @return {Roo.ContentPanel} The active panel or null
43611 getActivePanel : function(){
43612 return this.activePanel;
43615 validateVisibility : function(){
43616 if(this.panels.getCount() < 1){
43617 this.updateTitle(" ");
43618 this.closeBtn.hide();
43621 if(!this.isVisible()){
43628 * Adds the passed ContentPanel(s) to this region.
43629 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43630 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
43632 add : function(panel){
43633 if(arguments.length > 1){
43634 for(var i = 0, len = arguments.length; i < len; i++) {
43635 this.add(arguments[i]);
43639 if(this.hasPanel(panel)){
43640 this.showPanel(panel);
43643 panel.setRegion(this);
43644 this.panels.add(panel);
43645 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
43646 this.bodyEl.dom.appendChild(panel.getEl().dom);
43647 if(panel.background !== true){
43648 this.setActivePanel(panel);
43650 this.fireEvent("paneladded", this, panel);
43656 this.initPanelAsTab(panel);
43658 if(panel.background !== true){
43659 this.tabs.activate(panel.getEl().id);
43661 this.fireEvent("paneladded", this, panel);
43666 * Hides the tab for the specified panel.
43667 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43669 hidePanel : function(panel){
43670 if(this.tabs && (panel = this.getPanel(panel))){
43671 this.tabs.hideTab(panel.getEl().id);
43676 * Unhides the tab for a previously hidden panel.
43677 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43679 unhidePanel : function(panel){
43680 if(this.tabs && (panel = this.getPanel(panel))){
43681 this.tabs.unhideTab(panel.getEl().id);
43685 clearPanels : function(){
43686 while(this.panels.getCount() > 0){
43687 this.remove(this.panels.first());
43692 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43693 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43694 * @param {Boolean} preservePanel Overrides the config preservePanel option
43695 * @return {Roo.ContentPanel} The panel that was removed
43697 remove : function(panel, preservePanel){
43698 panel = this.getPanel(panel);
43703 this.fireEvent("beforeremove", this, panel, e);
43704 if(e.cancel === true){
43707 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
43708 var panelId = panel.getId();
43709 this.panels.removeKey(panelId);
43711 document.body.appendChild(panel.getEl().dom);
43714 this.tabs.removeTab(panel.getEl().id);
43715 }else if (!preservePanel){
43716 this.bodyEl.dom.removeChild(panel.getEl().dom);
43718 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
43719 var p = this.panels.first();
43720 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
43721 tempEl.appendChild(p.getEl().dom);
43722 this.bodyEl.update("");
43723 this.bodyEl.dom.appendChild(p.getEl().dom);
43725 this.updateTitle(p.getTitle());
43727 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43728 this.setActivePanel(p);
43730 panel.setRegion(null);
43731 if(this.activePanel == panel){
43732 this.activePanel = null;
43734 if(this.config.autoDestroy !== false && preservePanel !== true){
43735 try{panel.destroy();}catch(e){}
43737 this.fireEvent("panelremoved", this, panel);
43742 * Returns the TabPanel component used by this region
43743 * @return {Roo.TabPanel}
43745 getTabs : function(){
43749 createTool : function(parentEl, className){
43750 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
43751 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
43752 btn.addClassOnOver("x-layout-tools-button-over");
43757 * Ext JS Library 1.1.1
43758 * Copyright(c) 2006-2007, Ext JS, LLC.
43760 * Originally Released Under LGPL - original licence link has changed is not relivant.
43763 * <script type="text/javascript">
43769 * @class Roo.SplitLayoutRegion
43770 * @extends Roo.LayoutRegion
43771 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
43773 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
43774 this.cursor = cursor;
43775 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
43778 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
43779 splitTip : "Drag to resize.",
43780 collapsibleSplitTip : "Drag to resize. Double click to hide.",
43781 useSplitTips : false,
43783 applyConfig : function(config){
43784 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
43787 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
43788 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
43789 /** The SplitBar for this region
43790 * @type Roo.SplitBar */
43791 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
43792 this.split.on("moved", this.onSplitMove, this);
43793 this.split.useShim = config.useShim === true;
43794 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
43795 if(this.useSplitTips){
43796 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
43798 if(config.collapsible){
43799 this.split.el.on("dblclick", this.collapse, this);
43802 if(typeof config.minSize != "undefined"){
43803 this.split.minSize = config.minSize;
43805 if(typeof config.maxSize != "undefined"){
43806 this.split.maxSize = config.maxSize;
43808 if(config.hideWhenEmpty || config.hidden || config.collapsed){
43809 this.hideSplitter();
43814 getHMaxSize : function(){
43815 var cmax = this.config.maxSize || 10000;
43816 var center = this.mgr.getRegion("center");
43817 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
43820 getVMaxSize : function(){
43821 var cmax = this.config.maxSize || 10000;
43822 var center = this.mgr.getRegion("center");
43823 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
43826 onSplitMove : function(split, newSize){
43827 this.fireEvent("resized", this, newSize);
43831 * Returns the {@link Roo.SplitBar} for this region.
43832 * @return {Roo.SplitBar}
43834 getSplitBar : function(){
43839 this.hideSplitter();
43840 Roo.SplitLayoutRegion.superclass.hide.call(this);
43843 hideSplitter : function(){
43845 this.split.el.setLocation(-2000,-2000);
43846 this.split.el.hide();
43852 this.split.el.show();
43854 Roo.SplitLayoutRegion.superclass.show.call(this);
43857 beforeSlide: function(){
43858 if(Roo.isGecko){// firefox overflow auto bug workaround
43859 this.bodyEl.clip();
43860 if(this.tabs) this.tabs.bodyEl.clip();
43861 if(this.activePanel){
43862 this.activePanel.getEl().clip();
43864 if(this.activePanel.beforeSlide){
43865 this.activePanel.beforeSlide();
43871 afterSlide : function(){
43872 if(Roo.isGecko){// firefox overflow auto bug workaround
43873 this.bodyEl.unclip();
43874 if(this.tabs) this.tabs.bodyEl.unclip();
43875 if(this.activePanel){
43876 this.activePanel.getEl().unclip();
43877 if(this.activePanel.afterSlide){
43878 this.activePanel.afterSlide();
43884 initAutoHide : function(){
43885 if(this.autoHide !== false){
43886 if(!this.autoHideHd){
43887 var st = new Roo.util.DelayedTask(this.slideIn, this);
43888 this.autoHideHd = {
43889 "mouseout": function(e){
43890 if(!e.within(this.el, true)){
43894 "mouseover" : function(e){
43900 this.el.on(this.autoHideHd);
43904 clearAutoHide : function(){
43905 if(this.autoHide !== false){
43906 this.el.un("mouseout", this.autoHideHd.mouseout);
43907 this.el.un("mouseover", this.autoHideHd.mouseover);
43911 clearMonitor : function(){
43912 Roo.get(document).un("click", this.slideInIf, this);
43915 // these names are backwards but not changed for compat
43916 slideOut : function(){
43917 if(this.isSlid || this.el.hasActiveFx()){
43920 this.isSlid = true;
43921 if(this.collapseBtn){
43922 this.collapseBtn.hide();
43924 this.closeBtnState = this.closeBtn.getStyle('display');
43925 this.closeBtn.hide();
43927 this.stickBtn.show();
43930 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
43931 this.beforeSlide();
43932 this.el.setStyle("z-index", 10001);
43933 this.el.slideIn(this.getSlideAnchor(), {
43934 callback: function(){
43936 this.initAutoHide();
43937 Roo.get(document).on("click", this.slideInIf, this);
43938 this.fireEvent("slideshow", this);
43945 afterSlideIn : function(){
43946 this.clearAutoHide();
43947 this.isSlid = false;
43948 this.clearMonitor();
43949 this.el.setStyle("z-index", "");
43950 if(this.collapseBtn){
43951 this.collapseBtn.show();
43953 this.closeBtn.setStyle('display', this.closeBtnState);
43955 this.stickBtn.hide();
43957 this.fireEvent("slidehide", this);
43960 slideIn : function(cb){
43961 if(!this.isSlid || this.el.hasActiveFx()){
43965 this.isSlid = false;
43966 this.beforeSlide();
43967 this.el.slideOut(this.getSlideAnchor(), {
43968 callback: function(){
43969 this.el.setLeftTop(-10000, -10000);
43971 this.afterSlideIn();
43979 slideInIf : function(e){
43980 if(!e.within(this.el)){
43985 animateCollapse : function(){
43986 this.beforeSlide();
43987 this.el.setStyle("z-index", 20000);
43988 var anchor = this.getSlideAnchor();
43989 this.el.slideOut(anchor, {
43990 callback : function(){
43991 this.el.setStyle("z-index", "");
43992 this.collapsedEl.slideIn(anchor, {duration:.3});
43994 this.el.setLocation(-10000,-10000);
43996 this.fireEvent("collapsed", this);
44003 animateExpand : function(){
44004 this.beforeSlide();
44005 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
44006 this.el.setStyle("z-index", 20000);
44007 this.collapsedEl.hide({
44010 this.el.slideIn(this.getSlideAnchor(), {
44011 callback : function(){
44012 this.el.setStyle("z-index", "");
44015 this.split.el.show();
44017 this.fireEvent("invalidated", this);
44018 this.fireEvent("expanded", this);
44046 getAnchor : function(){
44047 return this.anchors[this.position];
44050 getCollapseAnchor : function(){
44051 return this.canchors[this.position];
44054 getSlideAnchor : function(){
44055 return this.sanchors[this.position];
44058 getAlignAdj : function(){
44059 var cm = this.cmargins;
44060 switch(this.position){
44076 getExpandAdj : function(){
44077 var c = this.collapsedEl, cm = this.cmargins;
44078 switch(this.position){
44080 return [-(cm.right+c.getWidth()+cm.left), 0];
44083 return [cm.right+c.getWidth()+cm.left, 0];
44086 return [0, -(cm.top+cm.bottom+c.getHeight())];
44089 return [0, cm.top+cm.bottom+c.getHeight()];
44095 * Ext JS Library 1.1.1
44096 * Copyright(c) 2006-2007, Ext JS, LLC.
44098 * Originally Released Under LGPL - original licence link has changed is not relivant.
44101 * <script type="text/javascript">
44104 * These classes are private internal classes
44106 Roo.CenterLayoutRegion = function(mgr, config){
44107 Roo.LayoutRegion.call(this, mgr, config, "center");
44108 this.visible = true;
44109 this.minWidth = config.minWidth || 20;
44110 this.minHeight = config.minHeight || 20;
44113 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
44115 // center panel can't be hidden
44119 // center panel can't be hidden
44122 getMinWidth: function(){
44123 return this.minWidth;
44126 getMinHeight: function(){
44127 return this.minHeight;
44132 Roo.NorthLayoutRegion = function(mgr, config){
44133 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
44135 this.split.placement = Roo.SplitBar.TOP;
44136 this.split.orientation = Roo.SplitBar.VERTICAL;
44137 this.split.el.addClass("x-layout-split-v");
44139 var size = config.initialSize || config.height;
44140 if(typeof size != "undefined"){
44141 this.el.setHeight(size);
44144 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
44145 orientation: Roo.SplitBar.VERTICAL,
44146 getBox : function(){
44147 if(this.collapsed){
44148 return this.collapsedEl.getBox();
44150 var box = this.el.getBox();
44152 box.height += this.split.el.getHeight();
44157 updateBox : function(box){
44158 if(this.split && !this.collapsed){
44159 box.height -= this.split.el.getHeight();
44160 this.split.el.setLeft(box.x);
44161 this.split.el.setTop(box.y+box.height);
44162 this.split.el.setWidth(box.width);
44164 if(this.collapsed){
44165 this.updateBody(box.width, null);
44167 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44171 Roo.SouthLayoutRegion = function(mgr, config){
44172 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
44174 this.split.placement = Roo.SplitBar.BOTTOM;
44175 this.split.orientation = Roo.SplitBar.VERTICAL;
44176 this.split.el.addClass("x-layout-split-v");
44178 var size = config.initialSize || config.height;
44179 if(typeof size != "undefined"){
44180 this.el.setHeight(size);
44183 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
44184 orientation: Roo.SplitBar.VERTICAL,
44185 getBox : function(){
44186 if(this.collapsed){
44187 return this.collapsedEl.getBox();
44189 var box = this.el.getBox();
44191 var sh = this.split.el.getHeight();
44198 updateBox : function(box){
44199 if(this.split && !this.collapsed){
44200 var sh = this.split.el.getHeight();
44203 this.split.el.setLeft(box.x);
44204 this.split.el.setTop(box.y-sh);
44205 this.split.el.setWidth(box.width);
44207 if(this.collapsed){
44208 this.updateBody(box.width, null);
44210 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44214 Roo.EastLayoutRegion = function(mgr, config){
44215 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
44217 this.split.placement = Roo.SplitBar.RIGHT;
44218 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44219 this.split.el.addClass("x-layout-split-h");
44221 var size = config.initialSize || config.width;
44222 if(typeof size != "undefined"){
44223 this.el.setWidth(size);
44226 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
44227 orientation: Roo.SplitBar.HORIZONTAL,
44228 getBox : function(){
44229 if(this.collapsed){
44230 return this.collapsedEl.getBox();
44232 var box = this.el.getBox();
44234 var sw = this.split.el.getWidth();
44241 updateBox : function(box){
44242 if(this.split && !this.collapsed){
44243 var sw = this.split.el.getWidth();
44245 this.split.el.setLeft(box.x);
44246 this.split.el.setTop(box.y);
44247 this.split.el.setHeight(box.height);
44250 if(this.collapsed){
44251 this.updateBody(null, box.height);
44253 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44257 Roo.WestLayoutRegion = function(mgr, config){
44258 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
44260 this.split.placement = Roo.SplitBar.LEFT;
44261 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44262 this.split.el.addClass("x-layout-split-h");
44264 var size = config.initialSize || config.width;
44265 if(typeof size != "undefined"){
44266 this.el.setWidth(size);
44269 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
44270 orientation: Roo.SplitBar.HORIZONTAL,
44271 getBox : function(){
44272 if(this.collapsed){
44273 return this.collapsedEl.getBox();
44275 var box = this.el.getBox();
44277 box.width += this.split.el.getWidth();
44282 updateBox : function(box){
44283 if(this.split && !this.collapsed){
44284 var sw = this.split.el.getWidth();
44286 this.split.el.setLeft(box.x+box.width);
44287 this.split.el.setTop(box.y);
44288 this.split.el.setHeight(box.height);
44290 if(this.collapsed){
44291 this.updateBody(null, box.height);
44293 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44298 * Ext JS Library 1.1.1
44299 * Copyright(c) 2006-2007, Ext JS, LLC.
44301 * Originally Released Under LGPL - original licence link has changed is not relivant.
44304 * <script type="text/javascript">
44309 * Private internal class for reading and applying state
44311 Roo.LayoutStateManager = function(layout){
44312 // default empty state
44321 Roo.LayoutStateManager.prototype = {
44322 init : function(layout, provider){
44323 this.provider = provider;
44324 var state = provider.get(layout.id+"-layout-state");
44326 var wasUpdating = layout.isUpdating();
44328 layout.beginUpdate();
44330 for(var key in state){
44331 if(typeof state[key] != "function"){
44332 var rstate = state[key];
44333 var r = layout.getRegion(key);
44336 r.resizeTo(rstate.size);
44338 if(rstate.collapsed == true){
44341 r.expand(null, true);
44347 layout.endUpdate();
44349 this.state = state;
44351 this.layout = layout;
44352 layout.on("regionresized", this.onRegionResized, this);
44353 layout.on("regioncollapsed", this.onRegionCollapsed, this);
44354 layout.on("regionexpanded", this.onRegionExpanded, this);
44357 storeState : function(){
44358 this.provider.set(this.layout.id+"-layout-state", this.state);
44361 onRegionResized : function(region, newSize){
44362 this.state[region.getPosition()].size = newSize;
44366 onRegionCollapsed : function(region){
44367 this.state[region.getPosition()].collapsed = true;
44371 onRegionExpanded : function(region){
44372 this.state[region.getPosition()].collapsed = false;
44377 * Ext JS Library 1.1.1
44378 * Copyright(c) 2006-2007, Ext JS, LLC.
44380 * Originally Released Under LGPL - original licence link has changed is not relivant.
44383 * <script type="text/javascript">
44386 * @class Roo.ContentPanel
44387 * @extends Roo.util.Observable
44388 * A basic ContentPanel element.
44389 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
44390 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
44391 * @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
44392 * @cfg {Boolean} closable True if the panel can be closed/removed
44393 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
44394 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
44395 * @cfg {Toolbar} toolbar A toolbar for this panel
44396 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
44397 * @cfg {String} title The title for this panel
44398 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
44399 * @cfg {String} url Calls {@link #setUrl} with this value
44400 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
44401 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
44403 * Create a new ContentPanel.
44404 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
44405 * @param {String/Object} config A string to set only the title or a config object
44406 * @param {String} content (optional) Set the HTML content for this panel
44407 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
44409 Roo.ContentPanel = function(el, config, content){
44413 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
44417 if (config && config.parentLayout) {
44418 el = config.parentLayout.el.createChild();
44421 if(el.autoCreate){ // xtype is available if this is called from factory
44425 this.el = Roo.get(el);
44426 if(!this.el && config && config.autoCreate){
44427 if(typeof config.autoCreate == "object"){
44428 if(!config.autoCreate.id){
44429 config.autoCreate.id = config.id||el;
44431 this.el = Roo.DomHelper.append(document.body,
44432 config.autoCreate, true);
44434 this.el = Roo.DomHelper.append(document.body,
44435 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
44438 this.closable = false;
44439 this.loaded = false;
44440 this.active = false;
44441 if(typeof config == "string"){
44442 this.title = config;
44444 Roo.apply(this, config);
44447 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
44448 this.wrapEl = this.el.wrap();
44449 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
44456 this.resizeEl = Roo.get(this.resizeEl, true);
44458 this.resizeEl = this.el;
44463 * Fires when this panel is activated.
44464 * @param {Roo.ContentPanel} this
44468 * @event deactivate
44469 * Fires when this panel is activated.
44470 * @param {Roo.ContentPanel} this
44472 "deactivate" : true,
44476 * Fires when this panel is resized if fitToFrame is true.
44477 * @param {Roo.ContentPanel} this
44478 * @param {Number} width The width after any component adjustments
44479 * @param {Number} height The height after any component adjustments
44483 if(this.autoScroll){
44484 this.resizeEl.setStyle("overflow", "auto");
44486 content = content || this.content;
44488 this.setContent(content);
44490 if(config && config.url){
44491 this.setUrl(this.url, this.params, this.loadOnce);
44496 Roo.ContentPanel.superclass.constructor.call(this);
44499 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
44501 setRegion : function(region){
44502 this.region = region;
44504 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
44506 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
44511 * Returns the toolbar for this Panel if one was configured.
44512 * @return {Roo.Toolbar}
44514 getToolbar : function(){
44515 return this.toolbar;
44518 setActiveState : function(active){
44519 this.active = active;
44521 this.fireEvent("deactivate", this);
44523 this.fireEvent("activate", this);
44527 * Updates this panel's element
44528 * @param {String} content The new content
44529 * @param {Boolean} loadScripts (optional) true to look for and process scripts
44531 setContent : function(content, loadScripts){
44532 this.el.update(content, loadScripts);
44535 ignoreResize : function(w, h){
44536 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
44539 this.lastSize = {width: w, height: h};
44544 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
44545 * @return {Roo.UpdateManager} The UpdateManager
44547 getUpdateManager : function(){
44548 return this.el.getUpdateManager();
44551 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
44552 * @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:
44555 url: "your-url.php",
44556 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
44557 callback: yourFunction,
44558 scope: yourObject, //(optional scope)
44561 text: "Loading...",
44566 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
44567 * 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.
44568 * @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}
44569 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
44570 * @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.
44571 * @return {Roo.ContentPanel} this
44574 var um = this.el.getUpdateManager();
44575 um.update.apply(um, arguments);
44581 * 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.
44582 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
44583 * @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)
44584 * @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)
44585 * @return {Roo.UpdateManager} The UpdateManager
44587 setUrl : function(url, params, loadOnce){
44588 if(this.refreshDelegate){
44589 this.removeListener("activate", this.refreshDelegate);
44591 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
44592 this.on("activate", this.refreshDelegate);
44593 return this.el.getUpdateManager();
44596 _handleRefresh : function(url, params, loadOnce){
44597 if(!loadOnce || !this.loaded){
44598 var updater = this.el.getUpdateManager();
44599 updater.update(url, params, this._setLoaded.createDelegate(this));
44603 _setLoaded : function(){
44604 this.loaded = true;
44608 * Returns this panel's id
44611 getId : function(){
44616 * Returns this panel's element - used by regiosn to add.
44617 * @return {Roo.Element}
44619 getEl : function(){
44620 return this.wrapEl || this.el;
44623 adjustForComponents : function(width, height){
44624 if(this.resizeEl != this.el){
44625 width -= this.el.getFrameWidth('lr');
44626 height -= this.el.getFrameWidth('tb');
44629 var te = this.toolbar.getEl();
44630 height -= te.getHeight();
44631 te.setWidth(width);
44633 if(this.adjustments){
44634 width += this.adjustments[0];
44635 height += this.adjustments[1];
44637 return {"width": width, "height": height};
44640 setSize : function(width, height){
44641 if(this.fitToFrame && !this.ignoreResize(width, height)){
44642 if(this.fitContainer && this.resizeEl != this.el){
44643 this.el.setSize(width, height);
44645 var size = this.adjustForComponents(width, height);
44646 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
44647 this.fireEvent('resize', this, size.width, size.height);
44652 * Returns this panel's title
44655 getTitle : function(){
44660 * Set this panel's title
44661 * @param {String} title
44663 setTitle : function(title){
44664 this.title = title;
44666 this.region.updatePanelTitle(this, title);
44671 * Returns true is this panel was configured to be closable
44672 * @return {Boolean}
44674 isClosable : function(){
44675 return this.closable;
44678 beforeSlide : function(){
44680 this.resizeEl.clip();
44683 afterSlide : function(){
44685 this.resizeEl.unclip();
44689 * Force a content refresh from the URL specified in the {@link #setUrl} method.
44690 * Will fail silently if the {@link #setUrl} method has not been called.
44691 * This does not activate the panel, just updates its content.
44693 refresh : function(){
44694 if(this.refreshDelegate){
44695 this.loaded = false;
44696 this.refreshDelegate();
44701 * Destroys this panel
44703 destroy : function(){
44704 this.el.removeAllListeners();
44705 var tempEl = document.createElement("span");
44706 tempEl.appendChild(this.el.dom);
44707 tempEl.innerHTML = "";
44713 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
44723 * @param {Object} cfg Xtype definition of item to add.
44726 addxtype : function(cfg) {
44728 if (cfg.xtype.match(/^Form$/)) {
44729 var el = this.el.createChild();
44731 this.form = new Roo.form.Form(cfg);
44734 if ( this.form.allItems.length) this.form.render(el.dom);
44737 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
44741 var ret = new Roo[cfg.xtype](cfg);
44742 ret.render(false, ''); // render blank..
44752 * @class Roo.GridPanel
44753 * @extends Roo.ContentPanel
44755 * Create a new GridPanel.
44756 * @param {Roo.grid.Grid} grid The grid for this panel
44757 * @param {String/Object} config A string to set only the panel's title, or a config object
44759 Roo.GridPanel = function(grid, config){
44762 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
44763 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
44765 this.wrapper.dom.appendChild(grid.getGridEl().dom);
44767 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
44770 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
44772 // xtype created footer. - not sure if will work as we normally have to render first..
44773 if (this.footer && !this.footer.el && this.footer.xtype) {
44775 this.footer.container = this.grid.getView().getFooterPanel(true);
44776 this.footer.dataSource = this.grid.dataSource;
44777 this.footer = Roo.factory(this.footer, Roo);
44781 grid.monitorWindowResize = false; // turn off autosizing
44782 grid.autoHeight = false;
44783 grid.autoWidth = false;
44785 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
44788 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
44789 getId : function(){
44790 return this.grid.id;
44794 * Returns the grid for this panel
44795 * @return {Roo.grid.Grid}
44797 getGrid : function(){
44801 setSize : function(width, height){
44802 if(!this.ignoreResize(width, height)){
44803 var grid = this.grid;
44804 var size = this.adjustForComponents(width, height);
44805 grid.getGridEl().setSize(size.width, size.height);
44810 beforeSlide : function(){
44811 this.grid.getView().scroller.clip();
44814 afterSlide : function(){
44815 this.grid.getView().scroller.unclip();
44818 destroy : function(){
44819 this.grid.destroy();
44821 Roo.GridPanel.superclass.destroy.call(this);
44827 * @class Roo.NestedLayoutPanel
44828 * @extends Roo.ContentPanel
44830 * Create a new NestedLayoutPanel.
44833 * @param {Roo.BorderLayout} layout The layout for this panel
44834 * @param {String/Object} config A string to set only the title or a config object
44836 Roo.NestedLayoutPanel = function(layout, config)
44838 // construct with only one argument..
44839 /* FIXME - implement nicer consturctors
44840 if (layout.layout) {
44842 layout = config.layout;
44843 delete config.layout;
44845 if (layout.xtype && !layout.getEl) {
44846 // then layout needs constructing..
44847 layout = Roo.factory(layout, Roo);
44851 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
44853 layout.monitorWindowResize = false; // turn off autosizing
44854 this.layout = layout;
44855 this.layout.getEl().addClass("x-layout-nested-layout");
44861 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
44863 setSize : function(width, height){
44864 if(!this.ignoreResize(width, height)){
44865 var size = this.adjustForComponents(width, height);
44866 var el = this.layout.getEl();
44867 el.setSize(size.width, size.height);
44868 var touch = el.dom.offsetWidth;
44869 this.layout.layout();
44870 // ie requires a double layout on the first pass
44871 if(Roo.isIE && !this.initialized){
44872 this.initialized = true;
44873 this.layout.layout();
44878 // activate all subpanels if not currently active..
44880 setActiveState : function(active){
44881 this.active = active;
44883 this.fireEvent("deactivate", this);
44887 this.fireEvent("activate", this);
44888 // not sure if this should happen before or after..
44889 if (!this.layout) {
44890 return; // should not happen..
44893 for (var r in this.layout.regions) {
44894 reg = this.layout.getRegion(r);
44895 if (reg.getActivePanel()) {
44896 //reg.showPanel(reg.getActivePanel()); // force it to activate..
44897 reg.setActivePanel(reg.getActivePanel());
44900 if (!reg.panels.length) {
44903 reg.showPanel(reg.getPanel(0));
44912 * Returns the nested BorderLayout for this panel
44913 * @return {Roo.BorderLayout}
44915 getLayout : function(){
44916 return this.layout;
44920 * Adds a xtype elements to the layout of the nested panel
44924 xtype : 'ContentPanel',
44931 xtype : 'NestedLayoutPanel',
44937 items : [ ... list of content panels or nested layout panels.. ]
44941 * @param {Object} cfg Xtype definition of item to add.
44943 addxtype : function(cfg) {
44944 return this.layout.addxtype(cfg);
44949 Roo.ScrollPanel = function(el, config, content){
44950 config = config || {};
44951 config.fitToFrame = true;
44952 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
44954 this.el.dom.style.overflow = "hidden";
44955 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
44956 this.el.removeClass("x-layout-inactive-content");
44957 this.el.on("mousewheel", this.onWheel, this);
44959 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
44960 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
44961 up.unselectable(); down.unselectable();
44962 up.on("click", this.scrollUp, this);
44963 down.on("click", this.scrollDown, this);
44964 up.addClassOnOver("x-scroller-btn-over");
44965 down.addClassOnOver("x-scroller-btn-over");
44966 up.addClassOnClick("x-scroller-btn-click");
44967 down.addClassOnClick("x-scroller-btn-click");
44968 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
44970 this.resizeEl = this.el;
44971 this.el = wrap; this.up = up; this.down = down;
44974 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
44976 wheelIncrement : 5,
44977 scrollUp : function(){
44978 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
44981 scrollDown : function(){
44982 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
44985 afterScroll : function(){
44986 var el = this.resizeEl;
44987 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
44988 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44989 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44992 setSize : function(){
44993 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
44994 this.afterScroll();
44997 onWheel : function(e){
44998 var d = e.getWheelDelta();
44999 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
45000 this.afterScroll();
45004 setContent : function(content, loadScripts){
45005 this.resizeEl.update(content, loadScripts);
45019 * @class Roo.TreePanel
45020 * @extends Roo.ContentPanel
45022 * Create a new TreePanel.
45023 * @param {String/Object} config A string to set only the panel's title, or a config object
45024 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
45026 Roo.TreePanel = function(config){
45027 var el = config.el;
45028 var tree = config.tree;
45029 delete config.tree;
45030 delete config.el; // hopefull!
45031 Roo.TreePanel.superclass.constructor.call(this, el, config);
45032 var treeEl = el.createChild();
45033 this.tree = new Roo.tree.TreePanel(treeEl , tree);
45034 //console.log(tree);
45035 this.on('activate', function()
45037 if (this.tree.rendered) {
45040 //console.log('render tree');
45041 this.tree.render();
45044 this.on('resize', function (cp, w, h) {
45045 this.tree.innerCt.setWidth(w);
45046 this.tree.innerCt.setHeight(h);
45047 this.tree.innerCt.setStyle('overflow-y', 'auto');
45054 Roo.extend(Roo.TreePanel, Roo.ContentPanel);
45068 * Ext JS Library 1.1.1
45069 * Copyright(c) 2006-2007, Ext JS, LLC.
45071 * Originally Released Under LGPL - original licence link has changed is not relivant.
45074 * <script type="text/javascript">
45079 * @class Roo.ReaderLayout
45080 * @extends Roo.BorderLayout
45081 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
45082 * center region containing two nested regions (a top one for a list view and one for item preview below),
45083 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
45084 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
45085 * expedites the setup of the overall layout and regions for this common application style.
45088 var reader = new Roo.ReaderLayout();
45089 var CP = Roo.ContentPanel; // shortcut for adding
45091 reader.beginUpdate();
45092 reader.add("north", new CP("north", "North"));
45093 reader.add("west", new CP("west", {title: "West"}));
45094 reader.add("east", new CP("east", {title: "East"}));
45096 reader.regions.listView.add(new CP("listView", "List"));
45097 reader.regions.preview.add(new CP("preview", "Preview"));
45098 reader.endUpdate();
45101 * Create a new ReaderLayout
45102 * @param {Object} config Configuration options
45103 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
45104 * document.body if omitted)
45106 Roo.ReaderLayout = function(config, renderTo){
45107 var c = config || {size:{}};
45108 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
45109 north: c.north !== false ? Roo.apply({
45113 }, c.north) : false,
45114 west: c.west !== false ? Roo.apply({
45122 margins:{left:5,right:0,bottom:5,top:5},
45123 cmargins:{left:5,right:5,bottom:5,top:5}
45124 }, c.west) : false,
45125 east: c.east !== false ? Roo.apply({
45133 margins:{left:0,right:5,bottom:5,top:5},
45134 cmargins:{left:5,right:5,bottom:5,top:5}
45135 }, c.east) : false,
45136 center: Roo.apply({
45137 tabPosition: 'top',
45141 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
45145 this.el.addClass('x-reader');
45147 this.beginUpdate();
45149 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
45150 south: c.preview !== false ? Roo.apply({
45157 cmargins:{top:5,left:0, right:0, bottom:0}
45158 }, c.preview) : false,
45159 center: Roo.apply({
45165 this.add('center', new Roo.NestedLayoutPanel(inner,
45166 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
45170 this.regions.preview = inner.getRegion('south');
45171 this.regions.listView = inner.getRegion('center');
45174 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
45176 * Ext JS Library 1.1.1
45177 * Copyright(c) 2006-2007, Ext JS, LLC.
45179 * Originally Released Under LGPL - original licence link has changed is not relivant.
45182 * <script type="text/javascript">
45186 * @class Roo.grid.Grid
45187 * @extends Roo.util.Observable
45188 * This class represents the primary interface of a component based grid control.
45189 * <br><br>Usage:<pre><code>
45190 var grid = new Roo.grid.Grid("my-container-id", {
45193 selModel: mySelectionModel,
45194 autoSizeColumns: true,
45195 monitorWindowResize: false,
45196 trackMouseOver: true
45201 * <b>Common Problems:</b><br/>
45202 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
45203 * element will correct this<br/>
45204 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
45205 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
45206 * are unpredictable.<br/>
45207 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
45208 * grid to calculate dimensions/offsets.<br/>
45210 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
45211 * The container MUST have some type of size defined for the grid to fill. The container will be
45212 * automatically set to position relative if it isn't already.
45213 * @param {Object} config A config object that sets properties on this grid.
45215 Roo.grid.Grid = function(container, config){
45216 // initialize the container
45217 this.container = Roo.get(container);
45218 this.container.update("");
45219 this.container.setStyle("overflow", "hidden");
45220 this.container.addClass('x-grid-container');
45222 this.id = this.container.id;
45224 Roo.apply(this, config);
45225 // check and correct shorthanded configs
45227 this.dataSource = this.ds;
45231 this.colModel = this.cm;
45235 this.selModel = this.sm;
45239 if (this.selModel) {
45240 this.selModel = Roo.factory(this.selModel, Roo.grid);
45241 this.sm = this.selModel;
45242 this.sm.xmodule = this.xmodule || false;
45244 if (typeof(this.colModel.config) == 'undefined') {
45245 this.colModel = new Roo.grid.ColumnModel(this.colModel);
45246 this.cm = this.colModel;
45247 this.cm.xmodule = this.xmodule || false;
45249 if (this.dataSource) {
45250 this.dataSource= Roo.factory(this.dataSource, Roo.data);
45251 this.ds = this.dataSource;
45252 this.ds.xmodule = this.xmodule || false;
45259 this.container.setWidth(this.width);
45263 this.container.setHeight(this.height);
45270 * The raw click event for the entire grid.
45271 * @param {Roo.EventObject} e
45276 * The raw dblclick event for the entire grid.
45277 * @param {Roo.EventObject} e
45281 * @event contextmenu
45282 * The raw contextmenu event for the entire grid.
45283 * @param {Roo.EventObject} e
45285 "contextmenu" : true,
45288 * The raw mousedown event for the entire grid.
45289 * @param {Roo.EventObject} e
45291 "mousedown" : true,
45294 * The raw mouseup event for the entire grid.
45295 * @param {Roo.EventObject} e
45300 * The raw mouseover event for the entire grid.
45301 * @param {Roo.EventObject} e
45303 "mouseover" : true,
45306 * The raw mouseout event for the entire grid.
45307 * @param {Roo.EventObject} e
45312 * The raw keypress event for the entire grid.
45313 * @param {Roo.EventObject} e
45318 * The raw keydown event for the entire grid.
45319 * @param {Roo.EventObject} e
45327 * Fires when a cell is clicked
45328 * @param {Grid} this
45329 * @param {Number} rowIndex
45330 * @param {Number} columnIndex
45331 * @param {Roo.EventObject} e
45333 "cellclick" : true,
45335 * @event celldblclick
45336 * Fires when a cell is double clicked
45337 * @param {Grid} this
45338 * @param {Number} rowIndex
45339 * @param {Number} columnIndex
45340 * @param {Roo.EventObject} e
45342 "celldblclick" : true,
45345 * Fires when a row is clicked
45346 * @param {Grid} this
45347 * @param {Number} rowIndex
45348 * @param {Roo.EventObject} e
45352 * @event rowdblclick
45353 * Fires when a row is double clicked
45354 * @param {Grid} this
45355 * @param {Number} rowIndex
45356 * @param {Roo.EventObject} e
45358 "rowdblclick" : true,
45360 * @event headerclick
45361 * Fires when a header is clicked
45362 * @param {Grid} this
45363 * @param {Number} columnIndex
45364 * @param {Roo.EventObject} e
45366 "headerclick" : true,
45368 * @event headerdblclick
45369 * Fires when a header cell is double clicked
45370 * @param {Grid} this
45371 * @param {Number} columnIndex
45372 * @param {Roo.EventObject} e
45374 "headerdblclick" : true,
45376 * @event rowcontextmenu
45377 * Fires when a row is right clicked
45378 * @param {Grid} this
45379 * @param {Number} rowIndex
45380 * @param {Roo.EventObject} e
45382 "rowcontextmenu" : true,
45384 * @event cellcontextmenu
45385 * Fires when a cell is right clicked
45386 * @param {Grid} this
45387 * @param {Number} rowIndex
45388 * @param {Number} cellIndex
45389 * @param {Roo.EventObject} e
45391 "cellcontextmenu" : true,
45393 * @event headercontextmenu
45394 * Fires when a header is right clicked
45395 * @param {Grid} this
45396 * @param {Number} columnIndex
45397 * @param {Roo.EventObject} e
45399 "headercontextmenu" : true,
45401 * @event bodyscroll
45402 * Fires when the body element is scrolled
45403 * @param {Number} scrollLeft
45404 * @param {Number} scrollTop
45406 "bodyscroll" : true,
45408 * @event columnresize
45409 * Fires when the user resizes a column
45410 * @param {Number} columnIndex
45411 * @param {Number} newSize
45413 "columnresize" : true,
45415 * @event columnmove
45416 * Fires when the user moves a column
45417 * @param {Number} oldIndex
45418 * @param {Number} newIndex
45420 "columnmove" : true,
45423 * Fires when row(s) start being dragged
45424 * @param {Grid} this
45425 * @param {Roo.GridDD} dd The drag drop object
45426 * @param {event} e The raw browser event
45428 "startdrag" : true,
45431 * Fires when a drag operation is complete
45432 * @param {Grid} this
45433 * @param {Roo.GridDD} dd The drag drop object
45434 * @param {event} e The raw browser event
45439 * Fires when dragged row(s) are dropped on a valid DD target
45440 * @param {Grid} this
45441 * @param {Roo.GridDD} dd The drag drop object
45442 * @param {String} targetId The target drag drop object
45443 * @param {event} e The raw browser event
45448 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
45449 * @param {Grid} this
45450 * @param {Roo.GridDD} dd The drag drop object
45451 * @param {String} targetId The target drag drop object
45452 * @param {event} e The raw browser event
45457 * Fires when the dragged row(s) first cross another DD target while being dragged
45458 * @param {Grid} this
45459 * @param {Roo.GridDD} dd The drag drop object
45460 * @param {String} targetId The target drag drop object
45461 * @param {event} e The raw browser event
45463 "dragenter" : true,
45466 * Fires when the dragged row(s) leave another DD target while being dragged
45467 * @param {Grid} this
45468 * @param {Roo.GridDD} dd The drag drop object
45469 * @param {String} targetId The target drag drop object
45470 * @param {event} e The raw browser event
45475 * Fires when the grid is rendered
45476 * @param {Grid} grid
45481 Roo.grid.Grid.superclass.constructor.call(this);
45483 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
45485 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
45487 minColumnWidth : 25,
45490 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
45491 * <b>on initial render.</b> It is more efficient to explicitly size the columns
45492 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
45494 autoSizeColumns : false,
45497 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
45499 autoSizeHeaders : true,
45502 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
45504 monitorWindowResize : true,
45507 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
45508 * rows measured to get a columns size. Default is 0 (all rows).
45510 maxRowsToMeasure : 0,
45513 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
45515 trackMouseOver : true,
45518 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
45520 enableDragDrop : false,
45523 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
45525 enableColumnMove : true,
45528 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
45530 enableColumnHide : true,
45533 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
45535 enableRowHeightSync : false,
45538 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
45543 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
45545 autoHeight : false,
45548 * @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.
45550 autoExpandColumn : false,
45553 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
45556 autoExpandMin : 50,
45559 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
45561 autoExpandMax : 1000,
45564 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
45569 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
45577 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
45578 * of a fixed width. Default is false.
45581 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
45584 * Called once after all setup has been completed and the grid is ready to be rendered.
45585 * @return {Roo.grid.Grid} this
45587 render : function(){
45588 var c = this.container;
45589 // try to detect autoHeight/width mode
45590 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
45591 this.autoHeight = true;
45593 var view = this.getView();
45596 c.on("click", this.onClick, this);
45597 c.on("dblclick", this.onDblClick, this);
45598 c.on("contextmenu", this.onContextMenu, this);
45599 c.on("keydown", this.onKeyDown, this);
45601 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
45603 this.getSelectionModel().init(this);
45608 this.loadMask = new Roo.LoadMask(this.container,
45609 Roo.apply({store:this.dataSource}, this.loadMask));
45613 if (this.toolbar && this.toolbar.xtype) {
45614 this.toolbar.container = this.getView().getHeaderPanel(true);
45615 this.toolbar = new Ext.Toolbar(this.toolbar);
45617 if (this.footer && this.footer.xtype) {
45618 this.footer.dataSource = this.getDataSource();
45619 this.footer.container = this.getView().getFooterPanel(true);
45620 this.footer = Roo.factory(this.footer, Roo);
45622 this.rendered = true;
45623 this.fireEvent('render', this);
45628 * Reconfigures the grid to use a different Store and Column Model.
45629 * The View will be bound to the new objects and refreshed.
45630 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
45631 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
45633 reconfigure : function(dataSource, colModel){
45635 this.loadMask.destroy();
45636 this.loadMask = new Roo.LoadMask(this.container,
45637 Roo.apply({store:dataSource}, this.loadMask));
45639 this.view.bind(dataSource, colModel);
45640 this.dataSource = dataSource;
45641 this.colModel = colModel;
45642 this.view.refresh(true);
45646 onKeyDown : function(e){
45647 this.fireEvent("keydown", e);
45651 * Destroy this grid.
45652 * @param {Boolean} removeEl True to remove the element
45654 destroy : function(removeEl, keepListeners){
45656 this.loadMask.destroy();
45658 var c = this.container;
45659 c.removeAllListeners();
45660 this.view.destroy();
45661 this.colModel.purgeListeners();
45662 if(!keepListeners){
45663 this.purgeListeners();
45666 if(removeEl === true){
45672 processEvent : function(name, e){
45673 this.fireEvent(name, e);
45674 var t = e.getTarget();
45676 var header = v.findHeaderIndex(t);
45677 if(header !== false){
45678 this.fireEvent("header" + name, this, header, e);
45680 var row = v.findRowIndex(t);
45681 var cell = v.findCellIndex(t);
45683 this.fireEvent("row" + name, this, row, e);
45684 if(cell !== false){
45685 this.fireEvent("cell" + name, this, row, cell, e);
45692 onClick : function(e){
45693 this.processEvent("click", e);
45697 onContextMenu : function(e, t){
45698 this.processEvent("contextmenu", e);
45702 onDblClick : function(e){
45703 this.processEvent("dblclick", e);
45707 walkCells : function(row, col, step, fn, scope){
45708 var cm = this.colModel, clen = cm.getColumnCount();
45709 var ds = this.dataSource, rlen = ds.getCount(), first = true;
45721 if(fn.call(scope || this, row, col, cm) === true){
45739 if(fn.call(scope || this, row, col, cm) === true){
45751 getSelections : function(){
45752 return this.selModel.getSelections();
45756 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
45757 * but if manual update is required this method will initiate it.
45759 autoSize : function(){
45761 this.view.layout();
45762 if(this.view.adjustForScroll){
45763 this.view.adjustForScroll();
45769 * Returns the grid's underlying element.
45770 * @return {Element} The element
45772 getGridEl : function(){
45773 return this.container;
45776 // private for compatibility, overridden by editor grid
45777 stopEditing : function(){},
45780 * Returns the grid's SelectionModel.
45781 * @return {SelectionModel}
45783 getSelectionModel : function(){
45784 if(!this.selModel){
45785 this.selModel = new Roo.grid.RowSelectionModel();
45787 return this.selModel;
45791 * Returns the grid's DataSource.
45792 * @return {DataSource}
45794 getDataSource : function(){
45795 return this.dataSource;
45799 * Returns the grid's ColumnModel.
45800 * @return {ColumnModel}
45802 getColumnModel : function(){
45803 return this.colModel;
45807 * Returns the grid's GridView object.
45808 * @return {GridView}
45810 getView : function(){
45812 this.view = new Roo.grid.GridView(this.viewConfig);
45817 * Called to get grid's drag proxy text, by default returns this.ddText.
45820 getDragDropText : function(){
45821 var count = this.selModel.getCount();
45822 return String.format(this.ddText, count, count == 1 ? '' : 's');
45826 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
45827 * %0 is replaced with the number of selected rows.
45830 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
45832 * Ext JS Library 1.1.1
45833 * Copyright(c) 2006-2007, Ext JS, LLC.
45835 * Originally Released Under LGPL - original licence link has changed is not relivant.
45838 * <script type="text/javascript">
45841 Roo.grid.AbstractGridView = function(){
45845 "beforerowremoved" : true,
45846 "beforerowsinserted" : true,
45847 "beforerefresh" : true,
45848 "rowremoved" : true,
45849 "rowsinserted" : true,
45850 "rowupdated" : true,
45853 Roo.grid.AbstractGridView.superclass.constructor.call(this);
45856 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
45857 rowClass : "x-grid-row",
45858 cellClass : "x-grid-cell",
45859 tdClass : "x-grid-td",
45860 hdClass : "x-grid-hd",
45861 splitClass : "x-grid-hd-split",
45863 init: function(grid){
45865 var cid = this.grid.getGridEl().id;
45866 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
45867 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
45868 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
45869 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
45872 getColumnRenderers : function(){
45873 var renderers = [];
45874 var cm = this.grid.colModel;
45875 var colCount = cm.getColumnCount();
45876 for(var i = 0; i < colCount; i++){
45877 renderers[i] = cm.getRenderer(i);
45882 getColumnIds : function(){
45884 var cm = this.grid.colModel;
45885 var colCount = cm.getColumnCount();
45886 for(var i = 0; i < colCount; i++){
45887 ids[i] = cm.getColumnId(i);
45892 getDataIndexes : function(){
45893 if(!this.indexMap){
45894 this.indexMap = this.buildIndexMap();
45896 return this.indexMap.colToData;
45899 getColumnIndexByDataIndex : function(dataIndex){
45900 if(!this.indexMap){
45901 this.indexMap = this.buildIndexMap();
45903 return this.indexMap.dataToCol[dataIndex];
45907 * Set a css style for a column dynamically.
45908 * @param {Number} colIndex The index of the column
45909 * @param {String} name The css property name
45910 * @param {String} value The css value
45912 setCSSStyle : function(colIndex, name, value){
45913 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
45914 Roo.util.CSS.updateRule(selector, name, value);
45917 generateRules : function(cm){
45918 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
45919 Roo.util.CSS.removeStyleSheet(rulesId);
45920 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
45921 var cid = cm.getColumnId(i);
45922 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
45923 this.tdSelector, cid, " {\n}\n",
45924 this.hdSelector, cid, " {\n}\n",
45925 this.splitSelector, cid, " {\n}\n");
45927 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
45931 * Ext JS Library 1.1.1
45932 * Copyright(c) 2006-2007, Ext JS, LLC.
45934 * Originally Released Under LGPL - original licence link has changed is not relivant.
45937 * <script type="text/javascript">
45941 // This is a support class used internally by the Grid components
45942 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
45944 this.view = grid.getView();
45945 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45946 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
45948 this.setHandleElId(Roo.id(hd));
45949 this.setOuterHandleElId(Roo.id(hd2));
45951 this.scroll = false;
45953 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
45955 getDragData : function(e){
45956 var t = Roo.lib.Event.getTarget(e);
45957 var h = this.view.findHeaderCell(t);
45959 return {ddel: h.firstChild, header:h};
45964 onInitDrag : function(e){
45965 this.view.headersDisabled = true;
45966 var clone = this.dragData.ddel.cloneNode(true);
45967 clone.id = Roo.id();
45968 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
45969 this.proxy.update(clone);
45973 afterValidDrop : function(){
45975 setTimeout(function(){
45976 v.headersDisabled = false;
45980 afterInvalidDrop : function(){
45982 setTimeout(function(){
45983 v.headersDisabled = false;
45989 * Ext JS Library 1.1.1
45990 * Copyright(c) 2006-2007, Ext JS, LLC.
45992 * Originally Released Under LGPL - original licence link has changed is not relivant.
45995 * <script type="text/javascript">
45998 // This is a support class used internally by the Grid components
45999 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
46001 this.view = grid.getView();
46002 // split the proxies so they don't interfere with mouse events
46003 this.proxyTop = Roo.DomHelper.append(document.body, {
46004 cls:"col-move-top", html:" "
46006 this.proxyBottom = Roo.DomHelper.append(document.body, {
46007 cls:"col-move-bottom", html:" "
46009 this.proxyTop.hide = this.proxyBottom.hide = function(){
46010 this.setLeftTop(-100,-100);
46011 this.setStyle("visibility", "hidden");
46013 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46014 // temporarily disabled
46015 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
46016 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
46018 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
46019 proxyOffsets : [-4, -9],
46020 fly: Roo.Element.fly,
46022 getTargetFromEvent : function(e){
46023 var t = Roo.lib.Event.getTarget(e);
46024 var cindex = this.view.findCellIndex(t);
46025 if(cindex !== false){
46026 return this.view.getHeaderCell(cindex);
46030 nextVisible : function(h){
46031 var v = this.view, cm = this.grid.colModel;
46034 if(!cm.isHidden(v.getCellIndex(h))){
46042 prevVisible : function(h){
46043 var v = this.view, cm = this.grid.colModel;
46046 if(!cm.isHidden(v.getCellIndex(h))){
46054 positionIndicator : function(h, n, e){
46055 var x = Roo.lib.Event.getPageX(e);
46056 var r = Roo.lib.Dom.getRegion(n.firstChild);
46057 var px, pt, py = r.top + this.proxyOffsets[1];
46058 if((r.right - x) <= (r.right-r.left)/2){
46059 px = r.right+this.view.borderWidth;
46065 var oldIndex = this.view.getCellIndex(h);
46066 var newIndex = this.view.getCellIndex(n);
46068 if(this.grid.colModel.isFixed(newIndex)){
46072 var locked = this.grid.colModel.isLocked(newIndex);
46077 if(oldIndex < newIndex){
46080 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
46083 px += this.proxyOffsets[0];
46084 this.proxyTop.setLeftTop(px, py);
46085 this.proxyTop.show();
46086 if(!this.bottomOffset){
46087 this.bottomOffset = this.view.mainHd.getHeight();
46089 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
46090 this.proxyBottom.show();
46094 onNodeEnter : function(n, dd, e, data){
46095 if(data.header != n){
46096 this.positionIndicator(data.header, n, e);
46100 onNodeOver : function(n, dd, e, data){
46101 var result = false;
46102 if(data.header != n){
46103 result = this.positionIndicator(data.header, n, e);
46106 this.proxyTop.hide();
46107 this.proxyBottom.hide();
46109 return result ? this.dropAllowed : this.dropNotAllowed;
46112 onNodeOut : function(n, dd, e, data){
46113 this.proxyTop.hide();
46114 this.proxyBottom.hide();
46117 onNodeDrop : function(n, dd, e, data){
46118 var h = data.header;
46120 var cm = this.grid.colModel;
46121 var x = Roo.lib.Event.getPageX(e);
46122 var r = Roo.lib.Dom.getRegion(n.firstChild);
46123 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
46124 var oldIndex = this.view.getCellIndex(h);
46125 var newIndex = this.view.getCellIndex(n);
46126 var locked = cm.isLocked(newIndex);
46130 if(oldIndex < newIndex){
46133 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
46136 cm.setLocked(oldIndex, locked, true);
46137 cm.moveColumn(oldIndex, newIndex);
46138 this.grid.fireEvent("columnmove", oldIndex, newIndex);
46146 * Ext JS Library 1.1.1
46147 * Copyright(c) 2006-2007, Ext JS, LLC.
46149 * Originally Released Under LGPL - original licence link has changed is not relivant.
46152 * <script type="text/javascript">
46156 * @class Roo.grid.GridView
46157 * @extends Roo.util.Observable
46160 * @param {Object} config
46162 Roo.grid.GridView = function(config){
46163 Roo.grid.GridView.superclass.constructor.call(this);
46166 Roo.apply(this, config);
46169 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
46172 * Override this function to apply custom css classes to rows during rendering
46173 * @param {Record} record The record
46174 * @param {Number} index
46175 * @method getRowClass
46177 rowClass : "x-grid-row",
46179 cellClass : "x-grid-col",
46181 tdClass : "x-grid-td",
46183 hdClass : "x-grid-hd",
46185 splitClass : "x-grid-split",
46187 sortClasses : ["sort-asc", "sort-desc"],
46189 enableMoveAnim : false,
46193 dh : Roo.DomHelper,
46195 fly : Roo.Element.fly,
46197 css : Roo.util.CSS,
46203 scrollIncrement : 22,
46205 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
46207 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
46209 bind : function(ds, cm){
46211 this.ds.un("load", this.onLoad, this);
46212 this.ds.un("datachanged", this.onDataChange, this);
46213 this.ds.un("add", this.onAdd, this);
46214 this.ds.un("remove", this.onRemove, this);
46215 this.ds.un("update", this.onUpdate, this);
46216 this.ds.un("clear", this.onClear, this);
46219 ds.on("load", this.onLoad, this);
46220 ds.on("datachanged", this.onDataChange, this);
46221 ds.on("add", this.onAdd, this);
46222 ds.on("remove", this.onRemove, this);
46223 ds.on("update", this.onUpdate, this);
46224 ds.on("clear", this.onClear, this);
46229 this.cm.un("widthchange", this.onColWidthChange, this);
46230 this.cm.un("headerchange", this.onHeaderChange, this);
46231 this.cm.un("hiddenchange", this.onHiddenChange, this);
46232 this.cm.un("columnmoved", this.onColumnMove, this);
46233 this.cm.un("columnlockchange", this.onColumnLock, this);
46236 this.generateRules(cm);
46237 cm.on("widthchange", this.onColWidthChange, this);
46238 cm.on("headerchange", this.onHeaderChange, this);
46239 cm.on("hiddenchange", this.onHiddenChange, this);
46240 cm.on("columnmoved", this.onColumnMove, this);
46241 cm.on("columnlockchange", this.onColumnLock, this);
46246 init: function(grid){
46247 Roo.grid.GridView.superclass.init.call(this, grid);
46249 this.bind(grid.dataSource, grid.colModel);
46251 grid.on("headerclick", this.handleHeaderClick, this);
46253 if(grid.trackMouseOver){
46254 grid.on("mouseover", this.onRowOver, this);
46255 grid.on("mouseout", this.onRowOut, this);
46257 grid.cancelTextSelection = function(){};
46258 this.gridId = grid.id;
46260 var tpls = this.templates || {};
46263 tpls.master = new Roo.Template(
46264 '<div class="x-grid" hidefocus="true">',
46265 '<div class="x-grid-topbar"></div>',
46266 '<div class="x-grid-scroller"><div></div></div>',
46267 '<div class="x-grid-locked">',
46268 '<div class="x-grid-header">{lockedHeader}</div>',
46269 '<div class="x-grid-body">{lockedBody}</div>',
46271 '<div class="x-grid-viewport">',
46272 '<div class="x-grid-header">{header}</div>',
46273 '<div class="x-grid-body">{body}</div>',
46275 '<div class="x-grid-bottombar"></div>',
46276 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
46277 '<div class="x-grid-resize-proxy"> </div>',
46280 tpls.master.disableformats = true;
46284 tpls.header = new Roo.Template(
46285 '<table border="0" cellspacing="0" cellpadding="0">',
46286 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
46289 tpls.header.disableformats = true;
46291 tpls.header.compile();
46294 tpls.hcell = new Roo.Template(
46295 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
46296 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
46299 tpls.hcell.disableFormats = true;
46301 tpls.hcell.compile();
46304 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
46305 tpls.hsplit.disableFormats = true;
46307 tpls.hsplit.compile();
46310 tpls.body = new Roo.Template(
46311 '<table border="0" cellspacing="0" cellpadding="0">',
46312 "<tbody>{rows}</tbody>",
46315 tpls.body.disableFormats = true;
46317 tpls.body.compile();
46320 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
46321 tpls.row.disableFormats = true;
46323 tpls.row.compile();
46326 tpls.cell = new Roo.Template(
46327 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
46328 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
46331 tpls.cell.disableFormats = true;
46333 tpls.cell.compile();
46335 this.templates = tpls;
46338 // remap these for backwards compat
46339 onColWidthChange : function(){
46340 this.updateColumns.apply(this, arguments);
46342 onHeaderChange : function(){
46343 this.updateHeaders.apply(this, arguments);
46345 onHiddenChange : function(){
46346 this.handleHiddenChange.apply(this, arguments);
46348 onColumnMove : function(){
46349 this.handleColumnMove.apply(this, arguments);
46351 onColumnLock : function(){
46352 this.handleLockChange.apply(this, arguments);
46355 onDataChange : function(){
46357 this.updateHeaderSortState();
46360 onClear : function(){
46364 onUpdate : function(ds, record){
46365 this.refreshRow(record);
46368 refreshRow : function(record){
46369 var ds = this.ds, index;
46370 if(typeof record == 'number'){
46372 record = ds.getAt(index);
46374 index = ds.indexOf(record);
46376 this.insertRows(ds, index, index, true);
46377 this.onRemove(ds, record, index+1, true);
46378 this.syncRowHeights(index, index);
46380 this.fireEvent("rowupdated", this, index, record);
46383 onAdd : function(ds, records, index){
46384 this.insertRows(ds, index, index + (records.length-1));
46387 onRemove : function(ds, record, index, isUpdate){
46388 if(isUpdate !== true){
46389 this.fireEvent("beforerowremoved", this, index, record);
46391 var bt = this.getBodyTable(), lt = this.getLockedTable();
46392 if(bt.rows[index]){
46393 bt.firstChild.removeChild(bt.rows[index]);
46395 if(lt.rows[index]){
46396 lt.firstChild.removeChild(lt.rows[index]);
46398 if(isUpdate !== true){
46399 this.stripeRows(index);
46400 this.syncRowHeights(index, index);
46402 this.fireEvent("rowremoved", this, index, record);
46406 onLoad : function(){
46407 this.scrollToTop();
46411 * Scrolls the grid to the top
46413 scrollToTop : function(){
46415 this.scroller.dom.scrollTop = 0;
46421 * Gets a panel in the header of the grid that can be used for toolbars etc.
46422 * After modifying the contents of this panel a call to grid.autoSize() may be
46423 * required to register any changes in size.
46424 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
46425 * @return Roo.Element
46427 getHeaderPanel : function(doShow){
46429 this.headerPanel.show();
46431 return this.headerPanel;
46435 * Gets a panel in the footer of the grid that can be used for toolbars etc.
46436 * After modifying the contents of this panel a call to grid.autoSize() may be
46437 * required to register any changes in size.
46438 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
46439 * @return Roo.Element
46441 getFooterPanel : function(doShow){
46443 this.footerPanel.show();
46445 return this.footerPanel;
46448 initElements : function(){
46449 var E = Roo.Element;
46450 var el = this.grid.getGridEl().dom.firstChild;
46451 var cs = el.childNodes;
46453 this.el = new E(el);
46454 this.headerPanel = new E(el.firstChild);
46455 this.headerPanel.enableDisplayMode("block");
46457 this.scroller = new E(cs[1]);
46458 this.scrollSizer = new E(this.scroller.dom.firstChild);
46460 this.lockedWrap = new E(cs[2]);
46461 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
46462 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
46464 this.mainWrap = new E(cs[3]);
46465 this.mainHd = new E(this.mainWrap.dom.firstChild);
46466 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
46468 this.footerPanel = new E(cs[4]);
46469 this.footerPanel.enableDisplayMode("block");
46471 this.focusEl = new E(cs[5]);
46472 this.focusEl.swallowEvent("click", true);
46473 this.resizeProxy = new E(cs[6]);
46475 this.headerSelector = String.format(
46476 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
46477 this.lockedHd.id, this.mainHd.id
46480 this.splitterSelector = String.format(
46481 '#{0} div.x-grid-split, #{1} div.x-grid-split',
46482 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
46485 idToCssName : function(s)
46487 return s.replace(/[^a-z0-9]+/ig, '-');
46490 getHeaderCell : function(index){
46491 return Roo.DomQuery.select(this.headerSelector)[index];
46494 getHeaderCellMeasure : function(index){
46495 return this.getHeaderCell(index).firstChild;
46498 getHeaderCellText : function(index){
46499 return this.getHeaderCell(index).firstChild.firstChild;
46502 getLockedTable : function(){
46503 return this.lockedBody.dom.firstChild;
46506 getBodyTable : function(){
46507 return this.mainBody.dom.firstChild;
46510 getLockedRow : function(index){
46511 return this.getLockedTable().rows[index];
46514 getRow : function(index){
46515 return this.getBodyTable().rows[index];
46518 getRowComposite : function(index){
46520 this.rowEl = new Roo.CompositeElementLite();
46522 var els = [], lrow, mrow;
46523 if(lrow = this.getLockedRow(index)){
46526 if(mrow = this.getRow(index)){
46529 this.rowEl.elements = els;
46533 getCell : function(rowIndex, colIndex){
46534 var locked = this.cm.getLockedCount();
46536 if(colIndex < locked){
46537 source = this.lockedBody.dom.firstChild;
46539 source = this.mainBody.dom.firstChild;
46540 colIndex -= locked;
46542 return source.rows[rowIndex].childNodes[colIndex];
46545 getCellText : function(rowIndex, colIndex){
46546 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
46549 getCellBox : function(cell){
46550 var b = this.fly(cell).getBox();
46551 if(Roo.isOpera){ // opera fails to report the Y
46552 b.y = cell.offsetTop + this.mainBody.getY();
46557 getCellIndex : function(cell){
46558 var id = String(cell.className).match(this.cellRE);
46560 return parseInt(id[1], 10);
46565 findHeaderIndex : function(n){
46566 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46567 return r ? this.getCellIndex(r) : false;
46570 findHeaderCell : function(n){
46571 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46572 return r ? r : false;
46575 findRowIndex : function(n){
46579 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
46580 return r ? r.rowIndex : false;
46583 findCellIndex : function(node){
46584 var stop = this.el.dom;
46585 while(node && node != stop){
46586 if(this.findRE.test(node.className)){
46587 return this.getCellIndex(node);
46589 node = node.parentNode;
46594 getColumnId : function(index){
46595 return this.cm.getColumnId(index);
46598 getSplitters : function(){
46599 if(this.splitterSelector){
46600 return Roo.DomQuery.select(this.splitterSelector);
46606 getSplitter : function(index){
46607 return this.getSplitters()[index];
46610 onRowOver : function(e, t){
46612 if((row = this.findRowIndex(t)) !== false){
46613 this.getRowComposite(row).addClass("x-grid-row-over");
46617 onRowOut : function(e, t){
46619 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
46620 this.getRowComposite(row).removeClass("x-grid-row-over");
46624 renderHeaders : function(){
46626 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
46627 var cb = [], lb = [], sb = [], lsb = [], p = {};
46628 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46629 p.cellId = "x-grid-hd-0-" + i;
46630 p.splitId = "x-grid-csplit-0-" + i;
46631 p.id = cm.getColumnId(i);
46632 p.title = cm.getColumnTooltip(i) || "";
46633 p.value = cm.getColumnHeader(i) || "";
46634 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
46635 if(!cm.isLocked(i)){
46636 cb[cb.length] = ct.apply(p);
46637 sb[sb.length] = st.apply(p);
46639 lb[lb.length] = ct.apply(p);
46640 lsb[lsb.length] = st.apply(p);
46643 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
46644 ht.apply({cells: cb.join(""), splits:sb.join("")})];
46647 updateHeaders : function(){
46648 var html = this.renderHeaders();
46649 this.lockedHd.update(html[0]);
46650 this.mainHd.update(html[1]);
46654 * Focuses the specified row.
46655 * @param {Number} row The row index
46657 focusRow : function(row){
46658 var x = this.scroller.dom.scrollLeft;
46659 this.focusCell(row, 0, false);
46660 this.scroller.dom.scrollLeft = x;
46664 * Focuses the specified cell.
46665 * @param {Number} row The row index
46666 * @param {Number} col The column index
46667 * @param {Boolean} hscroll false to disable horizontal scrolling
46669 focusCell : function(row, col, hscroll){
46670 var el = this.ensureVisible(row, col, hscroll);
46671 this.focusEl.alignTo(el, "tl-tl");
46673 this.focusEl.focus();
46675 this.focusEl.focus.defer(1, this.focusEl);
46680 * Scrolls the specified cell into view
46681 * @param {Number} row The row index
46682 * @param {Number} col The column index
46683 * @param {Boolean} hscroll false to disable horizontal scrolling
46685 ensureVisible : function(row, col, hscroll){
46686 if(typeof row != "number"){
46687 row = row.rowIndex;
46689 if(row < 0 && row >= this.ds.getCount()){
46692 col = (col !== undefined ? col : 0);
46693 var cm = this.grid.colModel;
46694 while(cm.isHidden(col)){
46698 var el = this.getCell(row, col);
46702 var c = this.scroller.dom;
46704 var ctop = parseInt(el.offsetTop, 10);
46705 var cleft = parseInt(el.offsetLeft, 10);
46706 var cbot = ctop + el.offsetHeight;
46707 var cright = cleft + el.offsetWidth;
46709 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
46710 var stop = parseInt(c.scrollTop, 10);
46711 var sleft = parseInt(c.scrollLeft, 10);
46712 var sbot = stop + ch;
46713 var sright = sleft + c.clientWidth;
46716 c.scrollTop = ctop;
46717 }else if(cbot > sbot){
46718 c.scrollTop = cbot-ch;
46721 if(hscroll !== false){
46723 c.scrollLeft = cleft;
46724 }else if(cright > sright){
46725 c.scrollLeft = cright-c.clientWidth;
46731 updateColumns : function(){
46732 this.grid.stopEditing();
46733 var cm = this.grid.colModel, colIds = this.getColumnIds();
46734 //var totalWidth = cm.getTotalWidth();
46736 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46737 //if(cm.isHidden(i)) continue;
46738 var w = cm.getColumnWidth(i);
46739 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46740 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46742 this.updateSplitters();
46745 generateRules : function(cm){
46746 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
46747 Roo.util.CSS.removeStyleSheet(rulesId);
46748 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46749 var cid = cm.getColumnId(i);
46751 if(cm.config[i].align){
46752 align = 'text-align:'+cm.config[i].align+';';
46755 if(cm.isHidden(i)){
46756 hidden = 'display:none;';
46758 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
46760 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
46761 this.hdSelector, cid, " {\n", align, width, "}\n",
46762 this.tdSelector, cid, " {\n",hidden,"\n}\n",
46763 this.splitSelector, cid, " {\n", hidden , "\n}\n");
46765 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46768 updateSplitters : function(){
46769 var cm = this.cm, s = this.getSplitters();
46770 if(s){ // splitters not created yet
46771 var pos = 0, locked = true;
46772 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46773 if(cm.isHidden(i)) continue;
46774 var w = cm.getColumnWidth(i);
46775 if(!cm.isLocked(i) && locked){
46780 s[i].style.left = (pos-this.splitOffset) + "px";
46785 handleHiddenChange : function(colModel, colIndex, hidden){
46787 this.hideColumn(colIndex);
46789 this.unhideColumn(colIndex);
46793 hideColumn : function(colIndex){
46794 var cid = this.getColumnId(colIndex);
46795 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
46796 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
46798 this.updateHeaders();
46800 this.updateSplitters();
46804 unhideColumn : function(colIndex){
46805 var cid = this.getColumnId(colIndex);
46806 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
46807 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
46810 this.updateHeaders();
46812 this.updateSplitters();
46816 insertRows : function(dm, firstRow, lastRow, isUpdate){
46817 if(firstRow == 0 && lastRow == dm.getCount()-1){
46821 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
46823 var s = this.getScrollState();
46824 var markup = this.renderRows(firstRow, lastRow);
46825 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
46826 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
46827 this.restoreScroll(s);
46829 this.fireEvent("rowsinserted", this, firstRow, lastRow);
46830 this.syncRowHeights(firstRow, lastRow);
46831 this.stripeRows(firstRow);
46837 bufferRows : function(markup, target, index){
46838 var before = null, trows = target.rows, tbody = target.tBodies[0];
46839 if(index < trows.length){
46840 before = trows[index];
46842 var b = document.createElement("div");
46843 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
46844 var rows = b.firstChild.rows;
46845 for(var i = 0, len = rows.length; i < len; i++){
46847 tbody.insertBefore(rows[0], before);
46849 tbody.appendChild(rows[0]);
46856 deleteRows : function(dm, firstRow, lastRow){
46857 if(dm.getRowCount()<1){
46858 this.fireEvent("beforerefresh", this);
46859 this.mainBody.update("");
46860 this.lockedBody.update("");
46861 this.fireEvent("refresh", this);
46863 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
46864 var bt = this.getBodyTable();
46865 var tbody = bt.firstChild;
46866 var rows = bt.rows;
46867 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
46868 tbody.removeChild(rows[firstRow]);
46870 this.stripeRows(firstRow);
46871 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
46875 updateRows : function(dataSource, firstRow, lastRow){
46876 var s = this.getScrollState();
46878 this.restoreScroll(s);
46881 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
46885 this.updateHeaderSortState();
46888 getScrollState : function(){
46889 var sb = this.scroller.dom;
46890 return {left: sb.scrollLeft, top: sb.scrollTop};
46893 stripeRows : function(startRow){
46894 if(!this.grid.stripeRows || this.ds.getCount() < 1){
46897 startRow = startRow || 0;
46898 var rows = this.getBodyTable().rows;
46899 var lrows = this.getLockedTable().rows;
46900 var cls = ' x-grid-row-alt ';
46901 for(var i = startRow, len = rows.length; i < len; i++){
46902 var row = rows[i], lrow = lrows[i];
46903 var isAlt = ((i+1) % 2 == 0);
46904 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
46905 if(isAlt == hasAlt){
46909 row.className += " x-grid-row-alt";
46911 row.className = row.className.replace("x-grid-row-alt", "");
46914 lrow.className = row.className;
46919 restoreScroll : function(state){
46920 var sb = this.scroller.dom;
46921 sb.scrollLeft = state.left;
46922 sb.scrollTop = state.top;
46926 syncScroll : function(){
46927 var sb = this.scroller.dom;
46928 var sh = this.mainHd.dom;
46929 var bs = this.mainBody.dom;
46930 var lv = this.lockedBody.dom;
46931 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
46932 lv.scrollTop = bs.scrollTop = sb.scrollTop;
46935 handleScroll : function(e){
46937 var sb = this.scroller.dom;
46938 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
46942 handleWheel : function(e){
46943 var d = e.getWheelDelta();
46944 this.scroller.dom.scrollTop -= d*22;
46945 // set this here to prevent jumpy scrolling on large tables
46946 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
46950 renderRows : function(startRow, endRow){
46951 // pull in all the crap needed to render rows
46952 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
46953 var colCount = cm.getColumnCount();
46955 if(ds.getCount() < 1){
46959 // build a map for all the columns
46961 for(var i = 0; i < colCount; i++){
46962 var name = cm.getDataIndex(i);
46964 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
46965 renderer : cm.getRenderer(i),
46966 id : cm.getColumnId(i),
46967 locked : cm.isLocked(i)
46971 startRow = startRow || 0;
46972 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
46974 // records to render
46975 var rs = ds.getRange(startRow, endRow);
46977 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
46980 // As much as I hate to duplicate code, this was branched because FireFox really hates
46981 // [].join("") on strings. The performance difference was substantial enough to
46982 // branch this function
46983 doRender : Roo.isGecko ?
46984 function(cs, rs, ds, startRow, colCount, stripe){
46985 var ts = this.templates, ct = ts.cell, rt = ts.row;
46987 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46988 for(var j = 0, len = rs.length; j < len; j++){
46989 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
46990 for(var i = 0; i < colCount; i++){
46992 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46994 p.css = p.attr = "";
46995 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46996 if(p.value == undefined || p.value === "") p.value = " ";
46997 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46998 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47000 var markup = ct.apply(p);
47008 if(stripe && ((rowIndex+1) % 2 == 0)){
47009 alt[0] = "x-grid-row-alt";
47012 alt[1] = " x-grid-dirty-row";
47015 if(this.getRowClass){
47016 alt[2] = this.getRowClass(r, rowIndex);
47018 rp.alt = alt.join(" ");
47019 lbuf+= rt.apply(rp);
47021 buf+= rt.apply(rp);
47023 return [lbuf, buf];
47025 function(cs, rs, ds, startRow, colCount, stripe){
47026 var ts = this.templates, ct = ts.cell, rt = ts.row;
47028 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47029 for(var j = 0, len = rs.length; j < len; j++){
47030 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
47031 for(var i = 0; i < colCount; i++){
47033 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47035 p.css = p.attr = "";
47036 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47037 if(p.value == undefined || p.value === "") p.value = " ";
47038 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47039 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47041 var markup = ct.apply(p);
47043 cb[cb.length] = markup;
47045 lcb[lcb.length] = markup;
47049 if(stripe && ((rowIndex+1) % 2 == 0)){
47050 alt[0] = "x-grid-row-alt";
47053 alt[1] = " x-grid-dirty-row";
47056 if(this.getRowClass){
47057 alt[2] = this.getRowClass(r, rowIndex);
47059 rp.alt = alt.join(" ");
47060 rp.cells = lcb.join("");
47061 lbuf[lbuf.length] = rt.apply(rp);
47062 rp.cells = cb.join("");
47063 buf[buf.length] = rt.apply(rp);
47065 return [lbuf.join(""), buf.join("")];
47068 renderBody : function(){
47069 var markup = this.renderRows();
47070 var bt = this.templates.body;
47071 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
47075 * Refreshes the grid
47076 * @param {Boolean} headersToo
47078 refresh : function(headersToo){
47079 this.fireEvent("beforerefresh", this);
47080 this.grid.stopEditing();
47081 var result = this.renderBody();
47082 this.lockedBody.update(result[0]);
47083 this.mainBody.update(result[1]);
47084 if(headersToo === true){
47085 this.updateHeaders();
47086 this.updateColumns();
47087 this.updateSplitters();
47088 this.updateHeaderSortState();
47090 this.syncRowHeights();
47092 this.fireEvent("refresh", this);
47095 handleColumnMove : function(cm, oldIndex, newIndex){
47096 this.indexMap = null;
47097 var s = this.getScrollState();
47098 this.refresh(true);
47099 this.restoreScroll(s);
47100 this.afterMove(newIndex);
47103 afterMove : function(colIndex){
47104 if(this.enableMoveAnim && Roo.enableFx){
47105 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
47109 updateCell : function(dm, rowIndex, dataIndex){
47110 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
47111 if(typeof colIndex == "undefined"){ // not present in grid
47114 var cm = this.grid.colModel;
47115 var cell = this.getCell(rowIndex, colIndex);
47116 var cellText = this.getCellText(rowIndex, colIndex);
47119 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
47120 id : cm.getColumnId(colIndex),
47121 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
47123 var renderer = cm.getRenderer(colIndex);
47124 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
47125 if(typeof val == "undefined" || val === "") val = " ";
47126 cellText.innerHTML = val;
47127 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
47128 this.syncRowHeights(rowIndex, rowIndex);
47131 calcColumnWidth : function(colIndex, maxRowsToMeasure){
47133 if(this.grid.autoSizeHeaders){
47134 var h = this.getHeaderCellMeasure(colIndex);
47135 maxWidth = Math.max(maxWidth, h.scrollWidth);
47138 if(this.cm.isLocked(colIndex)){
47139 tb = this.getLockedTable();
47142 tb = this.getBodyTable();
47143 index = colIndex - this.cm.getLockedCount();
47146 var rows = tb.rows;
47147 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
47148 for(var i = 0; i < stopIndex; i++){
47149 var cell = rows[i].childNodes[index].firstChild;
47150 maxWidth = Math.max(maxWidth, cell.scrollWidth);
47153 return maxWidth + /*margin for error in IE*/ 5;
47156 * Autofit a column to its content.
47157 * @param {Number} colIndex
47158 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
47160 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
47161 if(this.cm.isHidden(colIndex)){
47162 return; // can't calc a hidden column
47165 var cid = this.cm.getColumnId(colIndex);
47166 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
47167 if(this.grid.autoSizeHeaders){
47168 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
47171 var newWidth = this.calcColumnWidth(colIndex);
47172 this.cm.setColumnWidth(colIndex,
47173 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
47174 if(!suppressEvent){
47175 this.grid.fireEvent("columnresize", colIndex, newWidth);
47180 * Autofits all columns to their content and then expands to fit any extra space in the grid
47182 autoSizeColumns : function(){
47183 var cm = this.grid.colModel;
47184 var colCount = cm.getColumnCount();
47185 for(var i = 0; i < colCount; i++){
47186 this.autoSizeColumn(i, true, true);
47188 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
47191 this.updateColumns();
47197 * Autofits all columns to the grid's width proportionate with their current size
47198 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
47200 fitColumns : function(reserveScrollSpace){
47201 var cm = this.grid.colModel;
47202 var colCount = cm.getColumnCount();
47206 for (i = 0; i < colCount; i++){
47207 if(!cm.isHidden(i) && !cm.isFixed(i)){
47208 w = cm.getColumnWidth(i);
47214 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
47215 if(reserveScrollSpace){
47218 var frac = (avail - cm.getTotalWidth())/width;
47219 while (cols.length){
47222 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
47224 this.updateColumns();
47228 onRowSelect : function(rowIndex){
47229 var row = this.getRowComposite(rowIndex);
47230 row.addClass("x-grid-row-selected");
47233 onRowDeselect : function(rowIndex){
47234 var row = this.getRowComposite(rowIndex);
47235 row.removeClass("x-grid-row-selected");
47238 onCellSelect : function(row, col){
47239 var cell = this.getCell(row, col);
47241 Roo.fly(cell).addClass("x-grid-cell-selected");
47245 onCellDeselect : function(row, col){
47246 var cell = this.getCell(row, col);
47248 Roo.fly(cell).removeClass("x-grid-cell-selected");
47252 updateHeaderSortState : function(){
47253 var state = this.ds.getSortState();
47257 this.sortState = state;
47258 var sortColumn = this.cm.findColumnIndex(state.field);
47259 if(sortColumn != -1){
47260 var sortDir = state.direction;
47261 var sc = this.sortClasses;
47262 var hds = this.el.select(this.headerSelector).removeClass(sc);
47263 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
47267 handleHeaderClick : function(g, index){
47268 if(this.headersDisabled){
47271 var dm = g.dataSource, cm = g.colModel;
47272 if(!cm.isSortable(index)){
47276 dm.sort(cm.getDataIndex(index));
47280 destroy : function(){
47282 this.colMenu.removeAll();
47283 Roo.menu.MenuMgr.unregister(this.colMenu);
47284 this.colMenu.getEl().remove();
47285 delete this.colMenu;
47288 this.hmenu.removeAll();
47289 Roo.menu.MenuMgr.unregister(this.hmenu);
47290 this.hmenu.getEl().remove();
47293 if(this.grid.enableColumnMove){
47294 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47296 for(var dd in dds){
47297 if(!dds[dd].config.isTarget && dds[dd].dragElId){
47298 var elid = dds[dd].dragElId;
47300 Roo.get(elid).remove();
47301 } else if(dds[dd].config.isTarget){
47302 dds[dd].proxyTop.remove();
47303 dds[dd].proxyBottom.remove();
47306 if(Roo.dd.DDM.locationCache[dd]){
47307 delete Roo.dd.DDM.locationCache[dd];
47310 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47313 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
47314 this.bind(null, null);
47315 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
47318 handleLockChange : function(){
47319 this.refresh(true);
47322 onDenyColumnLock : function(){
47326 onDenyColumnHide : function(){
47330 handleHdMenuClick : function(item){
47331 var index = this.hdCtxIndex;
47332 var cm = this.cm, ds = this.ds;
47335 ds.sort(cm.getDataIndex(index), "ASC");
47338 ds.sort(cm.getDataIndex(index), "DESC");
47341 var lc = cm.getLockedCount();
47342 if(cm.getColumnCount(true) <= lc+1){
47343 this.onDenyColumnLock();
47347 cm.setLocked(index, true, true);
47348 cm.moveColumn(index, lc);
47349 this.grid.fireEvent("columnmove", index, lc);
47351 cm.setLocked(index, true);
47355 var lc = cm.getLockedCount();
47356 if((lc-1) != index){
47357 cm.setLocked(index, false, true);
47358 cm.moveColumn(index, lc-1);
47359 this.grid.fireEvent("columnmove", index, lc-1);
47361 cm.setLocked(index, false);
47365 index = cm.getIndexById(item.id.substr(4));
47367 if(item.checked && cm.getColumnCount(true) <= 1){
47368 this.onDenyColumnHide();
47371 cm.setHidden(index, item.checked);
47377 beforeColMenuShow : function(){
47378 var cm = this.cm, colCount = cm.getColumnCount();
47379 this.colMenu.removeAll();
47380 for(var i = 0; i < colCount; i++){
47381 this.colMenu.add(new Roo.menu.CheckItem({
47382 id: "col-"+cm.getColumnId(i),
47383 text: cm.getColumnHeader(i),
47384 checked: !cm.isHidden(i),
47390 handleHdCtx : function(g, index, e){
47392 var hd = this.getHeaderCell(index);
47393 this.hdCtxIndex = index;
47394 var ms = this.hmenu.items, cm = this.cm;
47395 ms.get("asc").setDisabled(!cm.isSortable(index));
47396 ms.get("desc").setDisabled(!cm.isSortable(index));
47397 if(this.grid.enableColLock !== false){
47398 ms.get("lock").setDisabled(cm.isLocked(index));
47399 ms.get("unlock").setDisabled(!cm.isLocked(index));
47401 this.hmenu.show(hd, "tl-bl");
47404 handleHdOver : function(e){
47405 var hd = this.findHeaderCell(e.getTarget());
47406 if(hd && !this.headersDisabled){
47407 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
47408 this.fly(hd).addClass("x-grid-hd-over");
47413 handleHdOut : function(e){
47414 var hd = this.findHeaderCell(e.getTarget());
47416 this.fly(hd).removeClass("x-grid-hd-over");
47420 handleSplitDblClick : function(e, t){
47421 var i = this.getCellIndex(t);
47422 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
47423 this.autoSizeColumn(i, true);
47428 render : function(){
47431 var colCount = cm.getColumnCount();
47433 if(this.grid.monitorWindowResize === true){
47434 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47436 var header = this.renderHeaders();
47437 var body = this.templates.body.apply({rows:""});
47438 var html = this.templates.master.apply({
47441 lockedHeader: header[0],
47445 //this.updateColumns();
47447 this.grid.getGridEl().dom.innerHTML = html;
47449 this.initElements();
47451 this.scroller.on("scroll", this.handleScroll, this);
47452 this.lockedBody.on("mousewheel", this.handleWheel, this);
47453 this.mainBody.on("mousewheel", this.handleWheel, this);
47455 this.mainHd.on("mouseover", this.handleHdOver, this);
47456 this.mainHd.on("mouseout", this.handleHdOut, this);
47457 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
47458 {delegate: "."+this.splitClass});
47460 this.lockedHd.on("mouseover", this.handleHdOver, this);
47461 this.lockedHd.on("mouseout", this.handleHdOut, this);
47462 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
47463 {delegate: "."+this.splitClass});
47465 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
47466 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47469 this.updateSplitters();
47471 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
47472 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47473 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47476 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
47477 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
47479 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
47480 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
47482 if(this.grid.enableColLock !== false){
47483 this.hmenu.add('-',
47484 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
47485 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
47488 if(this.grid.enableColumnHide !== false){
47490 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
47491 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
47492 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
47494 this.hmenu.add('-',
47495 {id:"columns", text: this.columnsText, menu: this.colMenu}
47498 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
47500 this.grid.on("headercontextmenu", this.handleHdCtx, this);
47503 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
47504 this.dd = new Roo.grid.GridDragZone(this.grid, {
47505 ddGroup : this.grid.ddGroup || 'GridDD'
47510 for(var i = 0; i < colCount; i++){
47511 if(cm.isHidden(i)){
47512 this.hideColumn(i);
47514 if(cm.config[i].align){
47515 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
47516 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
47520 this.updateHeaderSortState();
47522 this.beforeInitialResize();
47525 // two part rendering gives faster view to the user
47526 this.renderPhase2.defer(1, this);
47529 renderPhase2 : function(){
47530 // render the rows now
47532 if(this.grid.autoSizeColumns){
47533 this.autoSizeColumns();
47537 beforeInitialResize : function(){
47541 onColumnSplitterMoved : function(i, w){
47542 this.userResized = true;
47543 var cm = this.grid.colModel;
47544 cm.setColumnWidth(i, w, true);
47545 var cid = cm.getColumnId(i);
47546 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47547 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47548 this.updateSplitters();
47550 this.grid.fireEvent("columnresize", i, w);
47553 syncRowHeights : function(startIndex, endIndex){
47554 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
47555 startIndex = startIndex || 0;
47556 var mrows = this.getBodyTable().rows;
47557 var lrows = this.getLockedTable().rows;
47558 var len = mrows.length-1;
47559 endIndex = Math.min(endIndex || len, len);
47560 for(var i = startIndex; i <= endIndex; i++){
47561 var m = mrows[i], l = lrows[i];
47562 var h = Math.max(m.offsetHeight, l.offsetHeight);
47563 m.style.height = l.style.height = h + "px";
47568 layout : function(initialRender, is2ndPass){
47570 var auto = g.autoHeight;
47571 var scrollOffset = 16;
47572 var c = g.getGridEl(), cm = this.cm,
47573 expandCol = g.autoExpandColumn,
47575 //c.beginMeasure();
47577 if(!c.dom.offsetWidth){ // display:none?
47579 this.lockedWrap.show();
47580 this.mainWrap.show();
47585 var hasLock = this.cm.isLocked(0);
47587 var tbh = this.headerPanel.getHeight();
47588 var bbh = this.footerPanel.getHeight();
47591 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
47592 var newHeight = ch + c.getBorderWidth("tb");
47594 newHeight = Math.min(g.maxHeight, newHeight);
47596 c.setHeight(newHeight);
47600 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
47603 var s = this.scroller;
47605 var csize = c.getSize(true);
47607 this.el.setSize(csize.width, csize.height);
47609 this.headerPanel.setWidth(csize.width);
47610 this.footerPanel.setWidth(csize.width);
47612 var hdHeight = this.mainHd.getHeight();
47613 var vw = csize.width;
47614 var vh = csize.height - (tbh + bbh);
47618 var bt = this.getBodyTable();
47619 var ltWidth = hasLock ?
47620 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
47622 var scrollHeight = bt.offsetHeight;
47623 var scrollWidth = ltWidth + bt.offsetWidth;
47624 var vscroll = false, hscroll = false;
47626 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
47628 var lw = this.lockedWrap, mw = this.mainWrap;
47629 var lb = this.lockedBody, mb = this.mainBody;
47631 setTimeout(function(){
47632 var t = s.dom.offsetTop;
47633 var w = s.dom.clientWidth,
47634 h = s.dom.clientHeight;
47637 lw.setSize(ltWidth, h);
47639 mw.setLeftTop(ltWidth, t);
47640 mw.setSize(w-ltWidth, h);
47642 lb.setHeight(h-hdHeight);
47643 mb.setHeight(h-hdHeight);
47645 if(is2ndPass !== true && !gv.userResized && expandCol){
47646 // high speed resize without full column calculation
47648 var ci = cm.getIndexById(expandCol);
47650 ci = cm.findColumnIndex(expandCol);
47652 ci = Math.max(0, ci); // make sure it's got at least the first col.
47653 var expandId = cm.getColumnId(ci);
47654 var tw = cm.getTotalWidth(false);
47655 var currentWidth = cm.getColumnWidth(ci);
47656 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
47657 if(currentWidth != cw){
47658 cm.setColumnWidth(ci, cw, true);
47659 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47660 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47661 gv.updateSplitters();
47662 gv.layout(false, true);
47674 onWindowResize : function(){
47675 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
47681 appendFooter : function(parentEl){
47685 sortAscText : "Sort Ascending",
47686 sortDescText : "Sort Descending",
47687 lockText : "Lock Column",
47688 unlockText : "Unlock Column",
47689 columnsText : "Columns"
47693 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
47694 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
47695 this.proxy.el.addClass('x-grid3-col-dd');
47698 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
47699 handleMouseDown : function(e){
47703 callHandleMouseDown : function(e){
47704 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
47709 * Ext JS Library 1.1.1
47710 * Copyright(c) 2006-2007, Ext JS, LLC.
47712 * Originally Released Under LGPL - original licence link has changed is not relivant.
47715 * <script type="text/javascript">
47719 // This is a support class used internally by the Grid components
47720 Roo.grid.SplitDragZone = function(grid, hd, hd2){
47722 this.view = grid.getView();
47723 this.proxy = this.view.resizeProxy;
47724 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
47725 "gridSplitters" + this.grid.getGridEl().id, {
47726 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
47728 this.setHandleElId(Roo.id(hd));
47729 this.setOuterHandleElId(Roo.id(hd2));
47730 this.scroll = false;
47732 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
47733 fly: Roo.Element.fly,
47735 b4StartDrag : function(x, y){
47736 this.view.headersDisabled = true;
47737 this.proxy.setHeight(this.view.mainWrap.getHeight());
47738 var w = this.cm.getColumnWidth(this.cellIndex);
47739 var minw = Math.max(w-this.grid.minColumnWidth, 0);
47740 this.resetConstraints();
47741 this.setXConstraint(minw, 1000);
47742 this.setYConstraint(0, 0);
47743 this.minX = x - minw;
47744 this.maxX = x + 1000;
47746 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
47750 handleMouseDown : function(e){
47751 ev = Roo.EventObject.setEvent(e);
47752 var t = this.fly(ev.getTarget());
47753 if(t.hasClass("x-grid-split")){
47754 this.cellIndex = this.view.getCellIndex(t.dom);
47755 this.split = t.dom;
47756 this.cm = this.grid.colModel;
47757 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
47758 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
47763 endDrag : function(e){
47764 this.view.headersDisabled = false;
47765 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
47766 var diff = endX - this.startPos;
47767 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
47770 autoOffset : function(){
47771 this.setDelta(0,0);
47775 * Ext JS Library 1.1.1
47776 * Copyright(c) 2006-2007, Ext JS, LLC.
47778 * Originally Released Under LGPL - original licence link has changed is not relivant.
47781 * <script type="text/javascript">
47785 // This is a support class used internally by the Grid components
47786 Roo.grid.GridDragZone = function(grid, config){
47787 this.view = grid.getView();
47788 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
47789 if(this.view.lockedBody){
47790 this.setHandleElId(Roo.id(this.view.mainBody.dom));
47791 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
47793 this.scroll = false;
47795 this.ddel = document.createElement('div');
47796 this.ddel.className = 'x-grid-dd-wrap';
47799 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
47800 ddGroup : "GridDD",
47802 getDragData : function(e){
47803 var t = Roo.lib.Event.getTarget(e);
47804 var rowIndex = this.view.findRowIndex(t);
47805 if(rowIndex !== false){
47806 var sm = this.grid.selModel;
47807 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
47808 // sm.mouseDown(e, t);
47810 if (e.hasModifier()){
47811 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
47813 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
47818 onInitDrag : function(e){
47819 var data = this.dragData;
47820 this.ddel.innerHTML = this.grid.getDragDropText();
47821 this.proxy.update(this.ddel);
47822 // fire start drag?
47825 afterRepair : function(){
47826 this.dragging = false;
47829 getRepairXY : function(e, data){
47833 onEndDrag : function(data, e){
47837 onValidDrop : function(dd, e, id){
47842 beforeInvalidDrop : function(e, id){
47847 * Ext JS Library 1.1.1
47848 * Copyright(c) 2006-2007, Ext JS, LLC.
47850 * Originally Released Under LGPL - original licence link has changed is not relivant.
47853 * <script type="text/javascript">
47858 * @class Roo.grid.ColumnModel
47859 * @extends Roo.util.Observable
47860 * This is the default implementation of a ColumnModel used by the Grid. It defines
47861 * the columns in the grid.
47864 var colModel = new Roo.grid.ColumnModel([
47865 {header: "Ticker", width: 60, sortable: true, locked: true},
47866 {header: "Company Name", width: 150, sortable: true},
47867 {header: "Market Cap.", width: 100, sortable: true},
47868 {header: "$ Sales", width: 100, sortable: true, renderer: money},
47869 {header: "Employees", width: 100, sortable: true, resizable: false}
47874 * The config options listed for this class are options which may appear in each
47875 * individual column definition.
47876 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
47878 * @param {Object} config An Array of column config objects. See this class's
47879 * config objects for details.
47881 Roo.grid.ColumnModel = function(config){
47883 * The config passed into the constructor
47885 this.config = config;
47888 // if no id, create one
47889 // if the column does not have a dataIndex mapping,
47890 // map it to the order it is in the config
47891 for(var i = 0, len = config.length; i < len; i++){
47893 if(typeof c.dataIndex == "undefined"){
47896 if(typeof c.renderer == "string"){
47897 c.renderer = Roo.util.Format[c.renderer];
47899 if(typeof c.id == "undefined"){
47902 if(c.editor && c.editor.xtype){
47903 c.editor = Roo.factory(c.editor, Roo.grid);
47905 if(c.editor && c.editor.isFormField){
47906 c.editor = new Roo.grid.GridEditor(c.editor);
47908 this.lookup[c.id] = c;
47912 * The width of columns which have no width specified (defaults to 100)
47915 this.defaultWidth = 100;
47918 * Default sortable of columns which have no sortable specified (defaults to false)
47921 this.defaultSortable = false;
47925 * @event widthchange
47926 * Fires when the width of a column changes.
47927 * @param {ColumnModel} this
47928 * @param {Number} columnIndex The column index
47929 * @param {Number} newWidth The new width
47931 "widthchange": true,
47933 * @event headerchange
47934 * Fires when the text of a header changes.
47935 * @param {ColumnModel} this
47936 * @param {Number} columnIndex The column index
47937 * @param {Number} newText The new header text
47939 "headerchange": true,
47941 * @event hiddenchange
47942 * Fires when a column is hidden or "unhidden".
47943 * @param {ColumnModel} this
47944 * @param {Number} columnIndex The column index
47945 * @param {Boolean} hidden true if hidden, false otherwise
47947 "hiddenchange": true,
47949 * @event columnmoved
47950 * Fires when a column is moved.
47951 * @param {ColumnModel} this
47952 * @param {Number} oldIndex
47953 * @param {Number} newIndex
47955 "columnmoved" : true,
47957 * @event columlockchange
47958 * Fires when a column's locked state is changed
47959 * @param {ColumnModel} this
47960 * @param {Number} colIndex
47961 * @param {Boolean} locked true if locked
47963 "columnlockchange" : true
47965 Roo.grid.ColumnModel.superclass.constructor.call(this);
47967 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
47969 * @cfg {String} header The header text to display in the Grid view.
47972 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
47973 * {@link Roo.data.Record} definition from which to draw the column's value. If not
47974 * specified, the column's index is used as an index into the Record's data Array.
47977 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
47978 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
47981 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
47982 * Defaults to the value of the {@link #defaultSortable} property.
47983 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
47986 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
47989 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
47992 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
47995 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
47998 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
47999 * given the cell's data value. See {@link #setRenderer}. If not specified, the
48000 * default renderer uses the raw data value.
48003 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
48006 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
48010 * Returns the id of the column at the specified index.
48011 * @param {Number} index The column index
48012 * @return {String} the id
48014 getColumnId : function(index){
48015 return this.config[index].id;
48019 * Returns the column for a specified id.
48020 * @param {String} id The column id
48021 * @return {Object} the column
48023 getColumnById : function(id){
48024 return this.lookup[id];
48028 * Returns the index for a specified column id.
48029 * @param {String} id The column id
48030 * @return {Number} the index, or -1 if not found
48032 getIndexById : function(id){
48033 for(var i = 0, len = this.config.length; i < len; i++){
48034 if(this.config[i].id == id){
48041 * Returns the index for a specified column dataIndex.
48042 * @param {String} dataIndex The column dataIndex
48043 * @return {Number} the index, or -1 if not found
48046 findColumnIndex : function(dataIndex){
48047 for(var i = 0, len = this.config.length; i < len; i++){
48048 if(this.config[i].dataIndex == dataIndex){
48056 moveColumn : function(oldIndex, newIndex){
48057 var c = this.config[oldIndex];
48058 this.config.splice(oldIndex, 1);
48059 this.config.splice(newIndex, 0, c);
48060 this.dataMap = null;
48061 this.fireEvent("columnmoved", this, oldIndex, newIndex);
48064 isLocked : function(colIndex){
48065 return this.config[colIndex].locked === true;
48068 setLocked : function(colIndex, value, suppressEvent){
48069 if(this.isLocked(colIndex) == value){
48072 this.config[colIndex].locked = value;
48073 if(!suppressEvent){
48074 this.fireEvent("columnlockchange", this, colIndex, value);
48078 getTotalLockedWidth : function(){
48079 var totalWidth = 0;
48080 for(var i = 0; i < this.config.length; i++){
48081 if(this.isLocked(i) && !this.isHidden(i)){
48082 this.totalWidth += this.getColumnWidth(i);
48088 getLockedCount : function(){
48089 for(var i = 0, len = this.config.length; i < len; i++){
48090 if(!this.isLocked(i)){
48097 * Returns the number of columns.
48100 getColumnCount : function(visibleOnly){
48101 if(visibleOnly === true){
48103 for(var i = 0, len = this.config.length; i < len; i++){
48104 if(!this.isHidden(i)){
48110 return this.config.length;
48114 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
48115 * @param {Function} fn
48116 * @param {Object} scope (optional)
48117 * @return {Array} result
48119 getColumnsBy : function(fn, scope){
48121 for(var i = 0, len = this.config.length; i < len; i++){
48122 var c = this.config[i];
48123 if(fn.call(scope||this, c, i) === true){
48131 * Returns true if the specified column is sortable.
48132 * @param {Number} col The column index
48133 * @return {Boolean}
48135 isSortable : function(col){
48136 if(typeof this.config[col].sortable == "undefined"){
48137 return this.defaultSortable;
48139 return this.config[col].sortable;
48143 * Returns the rendering (formatting) function defined for the column.
48144 * @param {Number} col The column index.
48145 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
48147 getRenderer : function(col){
48148 if(!this.config[col].renderer){
48149 return Roo.grid.ColumnModel.defaultRenderer;
48151 return this.config[col].renderer;
48155 * Sets the rendering (formatting) function for a column.
48156 * @param {Number} col The column index
48157 * @param {Function} fn The function to use to process the cell's raw data
48158 * to return HTML markup for the grid view. The render function is called with
48159 * the following parameters:<ul>
48160 * <li>Data value.</li>
48161 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
48162 * <li>css A CSS style string to apply to the table cell.</li>
48163 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
48164 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
48165 * <li>Row index</li>
48166 * <li>Column index</li>
48167 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
48169 setRenderer : function(col, fn){
48170 this.config[col].renderer = fn;
48174 * Returns the width for the specified column.
48175 * @param {Number} col The column index
48178 getColumnWidth : function(col){
48179 return this.config[col].width || this.defaultWidth;
48183 * Sets the width for a column.
48184 * @param {Number} col The column index
48185 * @param {Number} width The new width
48187 setColumnWidth : function(col, width, suppressEvent){
48188 this.config[col].width = width;
48189 this.totalWidth = null;
48190 if(!suppressEvent){
48191 this.fireEvent("widthchange", this, col, width);
48196 * Returns the total width of all columns.
48197 * @param {Boolean} includeHidden True to include hidden column widths
48200 getTotalWidth : function(includeHidden){
48201 if(!this.totalWidth){
48202 this.totalWidth = 0;
48203 for(var i = 0, len = this.config.length; i < len; i++){
48204 if(includeHidden || !this.isHidden(i)){
48205 this.totalWidth += this.getColumnWidth(i);
48209 return this.totalWidth;
48213 * Returns the header for the specified column.
48214 * @param {Number} col The column index
48217 getColumnHeader : function(col){
48218 return this.config[col].header;
48222 * Sets the header for a column.
48223 * @param {Number} col The column index
48224 * @param {String} header The new header
48226 setColumnHeader : function(col, header){
48227 this.config[col].header = header;
48228 this.fireEvent("headerchange", this, col, header);
48232 * Returns the tooltip for the specified column.
48233 * @param {Number} col The column index
48236 getColumnTooltip : function(col){
48237 return this.config[col].tooltip;
48240 * Sets the tooltip for a column.
48241 * @param {Number} col The column index
48242 * @param {String} tooltip The new tooltip
48244 setColumnTooltip : function(col, tooltip){
48245 this.config[col].tooltip = tooltip;
48249 * Returns the dataIndex for the specified column.
48250 * @param {Number} col The column index
48253 getDataIndex : function(col){
48254 return this.config[col].dataIndex;
48258 * Sets the dataIndex for a column.
48259 * @param {Number} col The column index
48260 * @param {Number} dataIndex The new dataIndex
48262 setDataIndex : function(col, dataIndex){
48263 this.config[col].dataIndex = dataIndex;
48269 * Returns true if the cell is editable.
48270 * @param {Number} colIndex The column index
48271 * @param {Number} rowIndex The row index
48272 * @return {Boolean}
48274 isCellEditable : function(colIndex, rowIndex){
48275 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
48279 * Returns the editor defined for the cell/column.
48280 * return false or null to disable editing.
48281 * @param {Number} colIndex The column index
48282 * @param {Number} rowIndex The row index
48285 getCellEditor : function(colIndex, rowIndex){
48286 return this.config[colIndex].editor;
48290 * Sets if a column is editable.
48291 * @param {Number} col The column index
48292 * @param {Boolean} editable True if the column is editable
48294 setEditable : function(col, editable){
48295 this.config[col].editable = editable;
48300 * Returns true if the column is hidden.
48301 * @param {Number} colIndex The column index
48302 * @return {Boolean}
48304 isHidden : function(colIndex){
48305 return this.config[colIndex].hidden;
48310 * Returns true if the column width cannot be changed
48312 isFixed : function(colIndex){
48313 return this.config[colIndex].fixed;
48317 * Returns true if the column can be resized
48318 * @return {Boolean}
48320 isResizable : function(colIndex){
48321 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
48324 * Sets if a column is hidden.
48325 * @param {Number} colIndex The column index
48326 * @param {Boolean} hidden True if the column is hidden
48328 setHidden : function(colIndex, hidden){
48329 this.config[colIndex].hidden = hidden;
48330 this.totalWidth = null;
48331 this.fireEvent("hiddenchange", this, colIndex, hidden);
48335 * Sets the editor for a column.
48336 * @param {Number} col The column index
48337 * @param {Object} editor The editor object
48339 setEditor : function(col, editor){
48340 this.config[col].editor = editor;
48344 Roo.grid.ColumnModel.defaultRenderer = function(value){
48345 if(typeof value == "string" && value.length < 1){
48351 // Alias for backwards compatibility
48352 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
48355 * Ext JS Library 1.1.1
48356 * Copyright(c) 2006-2007, Ext JS, LLC.
48358 * Originally Released Under LGPL - original licence link has changed is not relivant.
48361 * <script type="text/javascript">
48365 * @class Roo.grid.AbstractSelectionModel
48366 * @extends Roo.util.Observable
48367 * Abstract base class for grid SelectionModels. It provides the interface that should be
48368 * implemented by descendant classes. This class should not be directly instantiated.
48371 Roo.grid.AbstractSelectionModel = function(){
48372 this.locked = false;
48373 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
48376 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
48377 /** @ignore Called by the grid automatically. Do not call directly. */
48378 init : function(grid){
48384 * Locks the selections.
48387 this.locked = true;
48391 * Unlocks the selections.
48393 unlock : function(){
48394 this.locked = false;
48398 * Returns true if the selections are locked.
48399 * @return {Boolean}
48401 isLocked : function(){
48402 return this.locked;
48406 * Ext JS Library 1.1.1
48407 * Copyright(c) 2006-2007, Ext JS, LLC.
48409 * Originally Released Under LGPL - original licence link has changed is not relivant.
48412 * <script type="text/javascript">
48415 * @extends Roo.grid.AbstractSelectionModel
48416 * @class Roo.grid.RowSelectionModel
48417 * The default SelectionModel used by {@link Roo.grid.Grid}.
48418 * It supports multiple selections and keyboard selection/navigation.
48420 * @param {Object} config
48422 Roo.grid.RowSelectionModel = function(config){
48423 Roo.apply(this, config);
48424 this.selections = new Roo.util.MixedCollection(false, function(o){
48429 this.lastActive = false;
48433 * @event selectionchange
48434 * Fires when the selection changes
48435 * @param {SelectionModel} this
48437 "selectionchange" : true,
48439 * @event afterselectionchange
48440 * Fires after the selection changes (eg. by key press or clicking)
48441 * @param {SelectionModel} this
48443 "afterselectionchange" : true,
48445 * @event beforerowselect
48446 * Fires when a row is selected being selected, return false to cancel.
48447 * @param {SelectionModel} this
48448 * @param {Number} rowIndex The selected index
48449 * @param {Boolean} keepExisting False if other selections will be cleared
48451 "beforerowselect" : true,
48454 * Fires when a row is selected.
48455 * @param {SelectionModel} this
48456 * @param {Number} rowIndex The selected index
48457 * @param {Roo.data.Record} r The record
48459 "rowselect" : true,
48461 * @event rowdeselect
48462 * Fires when a row is deselected.
48463 * @param {SelectionModel} this
48464 * @param {Number} rowIndex The selected index
48466 "rowdeselect" : true
48468 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
48469 this.locked = false;
48472 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
48474 * @cfg {Boolean} singleSelect
48475 * True to allow selection of only one row at a time (defaults to false)
48477 singleSelect : false,
48480 initEvents : function(){
48482 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
48483 this.grid.on("mousedown", this.handleMouseDown, this);
48484 }else{ // allow click to work like normal
48485 this.grid.on("rowclick", this.handleDragableRowClick, this);
48488 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
48489 "up" : function(e){
48491 this.selectPrevious(e.shiftKey);
48492 }else if(this.last !== false && this.lastActive !== false){
48493 var last = this.last;
48494 this.selectRange(this.last, this.lastActive-1);
48495 this.grid.getView().focusRow(this.lastActive);
48496 if(last !== false){
48500 this.selectFirstRow();
48502 this.fireEvent("afterselectionchange", this);
48504 "down" : function(e){
48506 this.selectNext(e.shiftKey);
48507 }else if(this.last !== false && this.lastActive !== false){
48508 var last = this.last;
48509 this.selectRange(this.last, this.lastActive+1);
48510 this.grid.getView().focusRow(this.lastActive);
48511 if(last !== false){
48515 this.selectFirstRow();
48517 this.fireEvent("afterselectionchange", this);
48522 var view = this.grid.view;
48523 view.on("refresh", this.onRefresh, this);
48524 view.on("rowupdated", this.onRowUpdated, this);
48525 view.on("rowremoved", this.onRemove, this);
48529 onRefresh : function(){
48530 var ds = this.grid.dataSource, i, v = this.grid.view;
48531 var s = this.selections;
48532 s.each(function(r){
48533 if((i = ds.indexOfId(r.id)) != -1){
48542 onRemove : function(v, index, r){
48543 this.selections.remove(r);
48547 onRowUpdated : function(v, index, r){
48548 if(this.isSelected(r)){
48549 v.onRowSelect(index);
48555 * @param {Array} records The records to select
48556 * @param {Boolean} keepExisting (optional) True to keep existing selections
48558 selectRecords : function(records, keepExisting){
48560 this.clearSelections();
48562 var ds = this.grid.dataSource;
48563 for(var i = 0, len = records.length; i < len; i++){
48564 this.selectRow(ds.indexOf(records[i]), true);
48569 * Gets the number of selected rows.
48572 getCount : function(){
48573 return this.selections.length;
48577 * Selects the first row in the grid.
48579 selectFirstRow : function(){
48584 * Select the last row.
48585 * @param {Boolean} keepExisting (optional) True to keep existing selections
48587 selectLastRow : function(keepExisting){
48588 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
48592 * Selects the row immediately following the last selected row.
48593 * @param {Boolean} keepExisting (optional) True to keep existing selections
48595 selectNext : function(keepExisting){
48596 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
48597 this.selectRow(this.last+1, keepExisting);
48598 this.grid.getView().focusRow(this.last);
48603 * Selects the row that precedes the last selected row.
48604 * @param {Boolean} keepExisting (optional) True to keep existing selections
48606 selectPrevious : function(keepExisting){
48608 this.selectRow(this.last-1, keepExisting);
48609 this.grid.getView().focusRow(this.last);
48614 * Returns the selected records
48615 * @return {Array} Array of selected records
48617 getSelections : function(){
48618 return [].concat(this.selections.items);
48622 * Returns the first selected record.
48625 getSelected : function(){
48626 return this.selections.itemAt(0);
48631 * Clears all selections.
48633 clearSelections : function(fast){
48634 if(this.locked) return;
48636 var ds = this.grid.dataSource;
48637 var s = this.selections;
48638 s.each(function(r){
48639 this.deselectRow(ds.indexOfId(r.id));
48643 this.selections.clear();
48650 * Selects all rows.
48652 selectAll : function(){
48653 if(this.locked) return;
48654 this.selections.clear();
48655 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
48656 this.selectRow(i, true);
48661 * Returns True if there is a selection.
48662 * @return {Boolean}
48664 hasSelection : function(){
48665 return this.selections.length > 0;
48669 * Returns True if the specified row is selected.
48670 * @param {Number/Record} record The record or index of the record to check
48671 * @return {Boolean}
48673 isSelected : function(index){
48674 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
48675 return (r && this.selections.key(r.id) ? true : false);
48679 * Returns True if the specified record id is selected.
48680 * @param {String} id The id of record to check
48681 * @return {Boolean}
48683 isIdSelected : function(id){
48684 return (this.selections.key(id) ? true : false);
48688 handleMouseDown : function(e, t){
48689 var view = this.grid.getView(), rowIndex;
48690 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
48693 if(e.shiftKey && this.last !== false){
48694 var last = this.last;
48695 this.selectRange(last, rowIndex, e.ctrlKey);
48696 this.last = last; // reset the last
48697 view.focusRow(rowIndex);
48699 var isSelected = this.isSelected(rowIndex);
48700 if(e.button !== 0 && isSelected){
48701 view.focusRow(rowIndex);
48702 }else if(e.ctrlKey && isSelected){
48703 this.deselectRow(rowIndex);
48704 }else if(!isSelected){
48705 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
48706 view.focusRow(rowIndex);
48709 this.fireEvent("afterselectionchange", this);
48712 handleDragableRowClick : function(grid, rowIndex, e)
48714 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
48715 this.selectRow(rowIndex, false);
48716 grid.view.focusRow(rowIndex);
48717 this.fireEvent("afterselectionchange", this);
48722 * Selects multiple rows.
48723 * @param {Array} rows Array of the indexes of the row to select
48724 * @param {Boolean} keepExisting (optional) True to keep existing selections
48726 selectRows : function(rows, keepExisting){
48728 this.clearSelections();
48730 for(var i = 0, len = rows.length; i < len; i++){
48731 this.selectRow(rows[i], true);
48736 * Selects a range of rows. All rows in between startRow and endRow are also selected.
48737 * @param {Number} startRow The index of the first row in the range
48738 * @param {Number} endRow The index of the last row in the range
48739 * @param {Boolean} keepExisting (optional) True to retain existing selections
48741 selectRange : function(startRow, endRow, keepExisting){
48742 if(this.locked) return;
48744 this.clearSelections();
48746 if(startRow <= endRow){
48747 for(var i = startRow; i <= endRow; i++){
48748 this.selectRow(i, true);
48751 for(var i = startRow; i >= endRow; i--){
48752 this.selectRow(i, true);
48758 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
48759 * @param {Number} startRow The index of the first row in the range
48760 * @param {Number} endRow The index of the last row in the range
48762 deselectRange : function(startRow, endRow, preventViewNotify){
48763 if(this.locked) return;
48764 for(var i = startRow; i <= endRow; i++){
48765 this.deselectRow(i, preventViewNotify);
48771 * @param {Number} row The index of the row to select
48772 * @param {Boolean} keepExisting (optional) True to keep existing selections
48774 selectRow : function(index, keepExisting, preventViewNotify){
48775 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
48776 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
48777 if(!keepExisting || this.singleSelect){
48778 this.clearSelections();
48780 var r = this.grid.dataSource.getAt(index);
48781 this.selections.add(r);
48782 this.last = this.lastActive = index;
48783 if(!preventViewNotify){
48784 this.grid.getView().onRowSelect(index);
48786 this.fireEvent("rowselect", this, index, r);
48787 this.fireEvent("selectionchange", this);
48793 * @param {Number} row The index of the row to deselect
48795 deselectRow : function(index, preventViewNotify){
48796 if(this.locked) return;
48797 if(this.last == index){
48800 if(this.lastActive == index){
48801 this.lastActive = false;
48803 var r = this.grid.dataSource.getAt(index);
48804 this.selections.remove(r);
48805 if(!preventViewNotify){
48806 this.grid.getView().onRowDeselect(index);
48808 this.fireEvent("rowdeselect", this, index);
48809 this.fireEvent("selectionchange", this);
48813 restoreLast : function(){
48815 this.last = this._last;
48820 acceptsNav : function(row, col, cm){
48821 return !cm.isHidden(col) && cm.isCellEditable(col, row);
48825 onEditorKey : function(field, e){
48826 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
48831 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
48833 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
48835 }else if(k == e.ENTER && !e.ctrlKey){
48839 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
48841 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
48843 }else if(k == e.ESC){
48847 g.startEditing(newCell[0], newCell[1]);
48852 * Ext JS Library 1.1.1
48853 * Copyright(c) 2006-2007, Ext JS, LLC.
48855 * Originally Released Under LGPL - original licence link has changed is not relivant.
48858 * <script type="text/javascript">
48861 * @class Roo.grid.CellSelectionModel
48862 * @extends Roo.grid.AbstractSelectionModel
48863 * This class provides the basic implementation for cell selection in a grid.
48865 * @param {Object} config The object containing the configuration of this model.
48867 Roo.grid.CellSelectionModel = function(config){
48868 Roo.apply(this, config);
48870 this.selection = null;
48874 * @event beforerowselect
48875 * Fires before a cell is selected.
48876 * @param {SelectionModel} this
48877 * @param {Number} rowIndex The selected row index
48878 * @param {Number} colIndex The selected cell index
48880 "beforecellselect" : true,
48882 * @event cellselect
48883 * Fires when a cell is selected.
48884 * @param {SelectionModel} this
48885 * @param {Number} rowIndex The selected row index
48886 * @param {Number} colIndex The selected cell index
48888 "cellselect" : true,
48890 * @event selectionchange
48891 * Fires when the active selection changes.
48892 * @param {SelectionModel} this
48893 * @param {Object} selection null for no selection or an object (o) with two properties
48895 <li>o.record: the record object for the row the selection is in</li>
48896 <li>o.cell: An array of [rowIndex, columnIndex]</li>
48899 "selectionchange" : true
48901 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
48904 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
48907 initEvents : function(){
48908 this.grid.on("mousedown", this.handleMouseDown, this);
48909 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
48910 var view = this.grid.view;
48911 view.on("refresh", this.onViewChange, this);
48912 view.on("rowupdated", this.onRowUpdated, this);
48913 view.on("beforerowremoved", this.clearSelections, this);
48914 view.on("beforerowsinserted", this.clearSelections, this);
48915 if(this.grid.isEditor){
48916 this.grid.on("beforeedit", this.beforeEdit, this);
48921 beforeEdit : function(e){
48922 this.select(e.row, e.column, false, true, e.record);
48926 onRowUpdated : function(v, index, r){
48927 if(this.selection && this.selection.record == r){
48928 v.onCellSelect(index, this.selection.cell[1]);
48933 onViewChange : function(){
48934 this.clearSelections(true);
48938 * Returns the currently selected cell,.
48939 * @return {Array} The selected cell (row, column) or null if none selected.
48941 getSelectedCell : function(){
48942 return this.selection ? this.selection.cell : null;
48946 * Clears all selections.
48947 * @param {Boolean} true to prevent the gridview from being notified about the change.
48949 clearSelections : function(preventNotify){
48950 var s = this.selection;
48952 if(preventNotify !== true){
48953 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
48955 this.selection = null;
48956 this.fireEvent("selectionchange", this, null);
48961 * Returns true if there is a selection.
48962 * @return {Boolean}
48964 hasSelection : function(){
48965 return this.selection ? true : false;
48969 handleMouseDown : function(e, t){
48970 var v = this.grid.getView();
48971 if(this.isLocked()){
48974 var row = v.findRowIndex(t);
48975 var cell = v.findCellIndex(t);
48976 if(row !== false && cell !== false){
48977 this.select(row, cell);
48983 * @param {Number} rowIndex
48984 * @param {Number} collIndex
48986 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
48987 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
48988 this.clearSelections();
48989 r = r || this.grid.dataSource.getAt(rowIndex);
48992 cell : [rowIndex, colIndex]
48994 if(!preventViewNotify){
48995 var v = this.grid.getView();
48996 v.onCellSelect(rowIndex, colIndex);
48997 if(preventFocus !== true){
48998 v.focusCell(rowIndex, colIndex);
49001 this.fireEvent("cellselect", this, rowIndex, colIndex);
49002 this.fireEvent("selectionchange", this, this.selection);
49007 isSelectable : function(rowIndex, colIndex, cm){
49008 return !cm.isHidden(colIndex);
49012 handleKeyDown : function(e){
49013 if(!e.isNavKeyPress()){
49016 var g = this.grid, s = this.selection;
49019 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
49021 this.select(cell[0], cell[1]);
49026 var walk = function(row, col, step){
49027 return g.walkCells(row, col, step, sm.isSelectable, sm);
49029 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
49035 newCell = walk(r, c-1, -1);
49037 newCell = walk(r, c+1, 1);
49041 newCell = walk(r+1, c, 1);
49044 newCell = walk(r-1, c, -1);
49047 newCell = walk(r, c+1, 1);
49050 newCell = walk(r, c-1, -1);
49053 if(g.isEditor && !g.editing){
49054 g.startEditing(r, c);
49061 this.select(newCell[0], newCell[1]);
49066 acceptsNav : function(row, col, cm){
49067 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49070 onEditorKey : function(field, e){
49071 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49074 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49076 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49079 }else if(k == e.ENTER && !e.ctrlKey){
49082 }else if(k == e.ESC){
49086 g.startEditing(newCell[0], newCell[1]);
49091 * Ext JS Library 1.1.1
49092 * Copyright(c) 2006-2007, Ext JS, LLC.
49094 * Originally Released Under LGPL - original licence link has changed is not relivant.
49097 * <script type="text/javascript">
49101 * @class Roo.grid.EditorGrid
49102 * @extends Roo.grid.Grid
49103 * Class for creating and editable grid.
49104 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49105 * The container MUST have some type of size defined for the grid to fill. The container will be
49106 * automatically set to position relative if it isn't already.
49107 * @param {Object} dataSource The data model to bind to
49108 * @param {Object} colModel The column model with info about this grid's columns
49110 Roo.grid.EditorGrid = function(container, config){
49111 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
49112 this.getGridEl().addClass("xedit-grid");
49114 if(!this.selModel){
49115 this.selModel = new Roo.grid.CellSelectionModel();
49118 this.activeEditor = null;
49122 * @event beforeedit
49123 * Fires before cell editing is triggered. The edit event object has the following properties <br />
49124 * <ul style="padding:5px;padding-left:16px;">
49125 * <li>grid - This grid</li>
49126 * <li>record - The record being edited</li>
49127 * <li>field - The field name being edited</li>
49128 * <li>value - The value for the field being edited.</li>
49129 * <li>row - The grid row index</li>
49130 * <li>column - The grid column index</li>
49131 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
49133 * @param {Object} e An edit event (see above for description)
49135 "beforeedit" : true,
49138 * Fires after a cell is edited. <br />
49139 * <ul style="padding:5px;padding-left:16px;">
49140 * <li>grid - This grid</li>
49141 * <li>record - The record being edited</li>
49142 * <li>field - The field name being edited</li>
49143 * <li>value - The value being set</li>
49144 * <li>originalValue - The original value for the field, before the edit.</li>
49145 * <li>row - The grid row index</li>
49146 * <li>column - The grid column index</li>
49148 * @param {Object} e An edit event (see above for description)
49150 "afteredit" : true,
49152 * @event validateedit
49153 * Fires after a cell is edited, but before the value is set in the record.
49154 * You can use this to modify the value being set in the field, Return false
49155 * to cancel the change. The edit event object has the following properties <br />
49156 * <ul style="padding:5px;padding-left:16px;">
49157 * <li>editor - This editor</li>
49158 * <li>grid - This grid</li>
49159 * <li>record - The record being edited</li>
49160 * <li>field - The field name being edited</li>
49161 * <li>value - The value being set</li>
49162 * <li>originalValue - The original value for the field, before the edit.</li>
49163 * <li>row - The grid row index</li>
49164 * <li>column - The grid column index</li>
49165 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
49167 * @param {Object} e An edit event (see above for description)
49169 "validateedit" : true
49171 this.on("bodyscroll", this.stopEditing, this);
49172 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
49175 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
49177 * @cfg {Number} clicksToEdit
49178 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
49185 trackMouseOver: false, // causes very odd FF errors
49187 onCellDblClick : function(g, row, col){
49188 this.startEditing(row, col);
49191 onEditComplete : function(ed, value, startValue){
49192 this.editing = false;
49193 this.activeEditor = null;
49194 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
49196 var field = this.colModel.getDataIndex(ed.col);
49201 originalValue: startValue,
49208 if(String(value) !== String(startValue)){
49210 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
49211 r.set(field, e.value);
49212 delete e.cancel; //?? why!!!
49213 this.fireEvent("afteredit", e);
49216 this.fireEvent("afteredit", e); // always fir it!
49218 this.view.focusCell(ed.row, ed.col);
49222 * Starts editing the specified for the specified row/column
49223 * @param {Number} rowIndex
49224 * @param {Number} colIndex
49226 startEditing : function(row, col){
49227 this.stopEditing();
49228 if(this.colModel.isCellEditable(col, row)){
49229 this.view.ensureVisible(row, col, true);
49230 var r = this.dataSource.getAt(row);
49231 var field = this.colModel.getDataIndex(col);
49236 value: r.data[field],
49241 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
49242 this.editing = true;
49243 var ed = this.colModel.getCellEditor(col, row);
49249 ed.render(ed.parentEl || document.body);
49252 (function(){ // complex but required for focus issues in safari, ie and opera
49256 ed.on("complete", this.onEditComplete, this, {single: true});
49257 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
49258 this.activeEditor = ed;
49259 var v = r.data[field];
49260 ed.startEdit(this.view.getCell(row, col), v);
49261 }).defer(50, this);
49267 * Stops any active editing
49269 stopEditing : function(){
49270 if(this.activeEditor){
49271 this.activeEditor.completeEdit();
49273 this.activeEditor = null;
49277 * Ext JS Library 1.1.1
49278 * Copyright(c) 2006-2007, Ext JS, LLC.
49280 * Originally Released Under LGPL - original licence link has changed is not relivant.
49283 * <script type="text/javascript">
49286 // private - not really -- you end up using it !
49287 // This is a support class used internally by the Grid components
49290 * @class Roo.grid.GridEditor
49291 * @extends Roo.Editor
49292 * Class for creating and editable grid elements.
49293 * @param {Object} config any settings (must include field)
49295 Roo.grid.GridEditor = function(field, config){
49296 if (!config && field.field) {
49298 field = Roo.factory(config.field, Roo.form);
49300 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
49301 field.monitorTab = false;
49304 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
49307 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
49310 alignment: "tl-tl",
49313 cls: "x-small-editor x-grid-editor",
49318 * Ext JS Library 1.1.1
49319 * Copyright(c) 2006-2007, Ext JS, LLC.
49321 * Originally Released Under LGPL - original licence link has changed is not relivant.
49324 * <script type="text/javascript">
49329 Roo.grid.PropertyRecord = Roo.data.Record.create([
49330 {name:'name',type:'string'}, 'value'
49334 Roo.grid.PropertyStore = function(grid, source){
49336 this.store = new Roo.data.Store({
49337 recordType : Roo.grid.PropertyRecord
49339 this.store.on('update', this.onUpdate, this);
49341 this.setSource(source);
49343 Roo.grid.PropertyStore.superclass.constructor.call(this);
49348 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
49349 setSource : function(o){
49351 this.store.removeAll();
49354 if(this.isEditableValue(o[k])){
49355 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
49358 this.store.loadRecords({records: data}, {}, true);
49361 onUpdate : function(ds, record, type){
49362 if(type == Roo.data.Record.EDIT){
49363 var v = record.data['value'];
49364 var oldValue = record.modified['value'];
49365 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
49366 this.source[record.id] = v;
49368 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
49375 getProperty : function(row){
49376 return this.store.getAt(row);
49379 isEditableValue: function(val){
49380 if(val && val instanceof Date){
49382 }else if(typeof val == 'object' || typeof val == 'function'){
49388 setValue : function(prop, value){
49389 this.source[prop] = value;
49390 this.store.getById(prop).set('value', value);
49393 getSource : function(){
49394 return this.source;
49398 Roo.grid.PropertyColumnModel = function(grid, store){
49401 g.PropertyColumnModel.superclass.constructor.call(this, [
49402 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
49403 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
49405 this.store = store;
49406 this.bselect = Roo.DomHelper.append(document.body, {
49407 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
49408 {tag: 'option', value: 'true', html: 'true'},
49409 {tag: 'option', value: 'false', html: 'false'}
49412 Roo.id(this.bselect);
49415 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
49416 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
49417 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
49418 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
49419 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
49421 this.renderCellDelegate = this.renderCell.createDelegate(this);
49422 this.renderPropDelegate = this.renderProp.createDelegate(this);
49425 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
49429 valueText : 'Value',
49431 dateFormat : 'm/j/Y',
49434 renderDate : function(dateVal){
49435 return dateVal.dateFormat(this.dateFormat);
49438 renderBool : function(bVal){
49439 return bVal ? 'true' : 'false';
49442 isCellEditable : function(colIndex, rowIndex){
49443 return colIndex == 1;
49446 getRenderer : function(col){
49448 this.renderCellDelegate : this.renderPropDelegate;
49451 renderProp : function(v){
49452 return this.getPropertyName(v);
49455 renderCell : function(val){
49457 if(val instanceof Date){
49458 rv = this.renderDate(val);
49459 }else if(typeof val == 'boolean'){
49460 rv = this.renderBool(val);
49462 return Roo.util.Format.htmlEncode(rv);
49465 getPropertyName : function(name){
49466 var pn = this.grid.propertyNames;
49467 return pn && pn[name] ? pn[name] : name;
49470 getCellEditor : function(colIndex, rowIndex){
49471 var p = this.store.getProperty(rowIndex);
49472 var n = p.data['name'], val = p.data['value'];
49474 if(typeof(this.grid.customEditors[n]) == 'string'){
49475 return this.editors[this.grid.customEditors[n]];
49477 if(typeof(this.grid.customEditors[n]) != 'undefined'){
49478 return this.grid.customEditors[n];
49480 if(val instanceof Date){
49481 return this.editors['date'];
49482 }else if(typeof val == 'number'){
49483 return this.editors['number'];
49484 }else if(typeof val == 'boolean'){
49485 return this.editors['boolean'];
49487 return this.editors['string'];
49493 * @class Roo.grid.PropertyGrid
49494 * @extends Roo.grid.EditorGrid
49495 * This class represents the interface of a component based property grid control.
49496 * <br><br>Usage:<pre><code>
49497 var grid = new Roo.grid.PropertyGrid("my-container-id", {
49505 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49506 * The container MUST have some type of size defined for the grid to fill. The container will be
49507 * automatically set to position relative if it isn't already.
49508 * @param {Object} config A config object that sets properties on this grid.
49510 Roo.grid.PropertyGrid = function(container, config){
49511 config = config || {};
49512 var store = new Roo.grid.PropertyStore(this);
49513 this.store = store;
49514 var cm = new Roo.grid.PropertyColumnModel(this, store);
49515 store.store.sort('name', 'ASC');
49516 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
49519 enableColLock:false,
49520 enableColumnMove:false,
49522 trackMouseOver: false,
49525 this.getGridEl().addClass('x-props-grid');
49526 this.lastEditRow = null;
49527 this.on('columnresize', this.onColumnResize, this);
49530 * @event beforepropertychange
49531 * Fires before a property changes (return false to stop?)
49532 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49533 * @param {String} id Record Id
49534 * @param {String} newval New Value
49535 * @param {String} oldval Old Value
49537 "beforepropertychange": true,
49539 * @event propertychange
49540 * Fires after a property changes
49541 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49542 * @param {String} id Record Id
49543 * @param {String} newval New Value
49544 * @param {String} oldval Old Value
49546 "propertychange": true
49548 this.customEditors = this.customEditors || {};
49550 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
49553 * @cfg {Object} customEditors map of colnames=> custom editors.
49554 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
49555 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
49556 * false disables editing of the field.
49560 * @cfg {Object} propertyNames map of property Names to their displayed value
49563 render : function(){
49564 Roo.grid.PropertyGrid.superclass.render.call(this);
49565 this.autoSize.defer(100, this);
49568 autoSize : function(){
49569 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
49571 this.view.fitColumns();
49575 onColumnResize : function(){
49576 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
49580 * Sets the data for the Grid
49581 * accepts a Key => Value object of all the elements avaiable.
49582 * @param {Object} data to appear in grid.
49584 setSource : function(source){
49585 this.store.setSource(source);
49589 * Gets all the data from the grid.
49590 * @return {Object} data data stored in grid
49592 getSource : function(){
49593 return this.store.getSource();
49597 * Ext JS Library 1.1.1
49598 * Copyright(c) 2006-2007, Ext JS, LLC.
49600 * Originally Released Under LGPL - original licence link has changed is not relivant.
49603 * <script type="text/javascript">
49607 * @class Roo.LoadMask
49608 * A simple utility class for generically masking elements while loading data. If the element being masked has
49609 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
49610 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
49611 * element's UpdateManager load indicator and will be destroyed after the initial load.
49613 * Create a new LoadMask
49614 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
49615 * @param {Object} config The config object
49617 Roo.LoadMask = function(el, config){
49618 this.el = Roo.get(el);
49619 Roo.apply(this, config);
49621 this.store.on('beforeload', this.onBeforeLoad, this);
49622 this.store.on('load', this.onLoad, this);
49623 this.store.on('loadexception', this.onLoad, this);
49624 this.removeMask = false;
49626 var um = this.el.getUpdateManager();
49627 um.showLoadIndicator = false; // disable the default indicator
49628 um.on('beforeupdate', this.onBeforeLoad, this);
49629 um.on('update', this.onLoad, this);
49630 um.on('failure', this.onLoad, this);
49631 this.removeMask = true;
49635 Roo.LoadMask.prototype = {
49637 * @cfg {Boolean} removeMask
49638 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
49639 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
49642 * @cfg {String} msg
49643 * The text to display in a centered loading message box (defaults to 'Loading...')
49645 msg : 'Loading...',
49647 * @cfg {String} msgCls
49648 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
49650 msgCls : 'x-mask-loading',
49653 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
49659 * Disables the mask to prevent it from being displayed
49661 disable : function(){
49662 this.disabled = true;
49666 * Enables the mask so that it can be displayed
49668 enable : function(){
49669 this.disabled = false;
49673 onLoad : function(){
49674 this.el.unmask(this.removeMask);
49678 onBeforeLoad : function(){
49679 if(!this.disabled){
49680 this.el.mask(this.msg, this.msgCls);
49685 destroy : function(){
49687 this.store.un('beforeload', this.onBeforeLoad, this);
49688 this.store.un('load', this.onLoad, this);
49689 this.store.un('loadexception', this.onLoad, this);
49691 var um = this.el.getUpdateManager();
49692 um.un('beforeupdate', this.onBeforeLoad, this);
49693 um.un('update', this.onLoad, this);
49694 um.un('failure', this.onLoad, this);
49699 * Ext JS Library 1.1.1
49700 * Copyright(c) 2006-2007, Ext JS, LLC.
49702 * Originally Released Under LGPL - original licence link has changed is not relivant.
49705 * <script type="text/javascript">
49707 Roo.XTemplate = function(){
49708 Roo.XTemplate.superclass.constructor.apply(this, arguments);
49711 s = ['<tpl>', s, '</tpl>'].join('');
49713 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
49715 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
49716 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
49717 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
49721 while(m = s.match(re)){
49722 var m2 = m[0].match(nameRe);
49723 var m3 = m[0].match(ifRe);
49724 var m4 = m[0].match(execRe);
49725 var exp = null, fn = null, exec = null;
49726 var name = m2 && m2[1] ? m2[1] : '';
49728 exp = m3 && m3[1] ? m3[1] : null;
49730 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
49734 exp = m4 && m4[1] ? m4[1] : null;
49736 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
49741 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
49742 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
49743 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
49753 s = s.replace(m[0], '{xtpl'+ id + '}');
49756 for(var i = tpls.length-1; i >= 0; --i){
49757 this.compileTpl(tpls[i]);
49759 this.master = tpls[tpls.length-1];
49762 Roo.extend(Roo.XTemplate, Roo.Template, {
49764 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
49766 applySubTemplate : function(id, values, parent){
49767 var t = this.tpls[id];
49768 if(t.test && !t.test.call(this, values, parent)){
49771 if(t.exec && t.exec.call(this, values, parent)){
49774 var vs = t.target ? t.target.call(this, values, parent) : values;
49775 parent = t.target ? values : parent;
49776 if(t.target && vs instanceof Array){
49778 for(var i = 0, len = vs.length; i < len; i++){
49779 buf[buf.length] = t.compiled.call(this, vs[i], parent);
49781 return buf.join('');
49783 return t.compiled.call(this, vs, parent);
49786 compileTpl : function(tpl){
49787 var fm = Roo.util.Format;
49788 var useF = this.disableFormats !== true;
49789 var sep = Roo.isGecko ? "+" : ",";
49790 var fn = function(m, name, format, args){
49791 if(name.substr(0, 4) == 'xtpl'){
49792 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
49795 if(name.indexOf('.') != -1){
49798 v = "values['" + name + "']";
49800 if(format && useF){
49801 args = args ? ',' + args : "";
49802 if(format.substr(0, 5) != "this."){
49803 format = "fm." + format + '(';
49805 format = 'this.call("'+ format.substr(5) + '", ';
49809 args= ''; format = "("+v+" === undefined ? '' : ";
49811 return "'"+ sep + format + v + args + ")"+sep+"'";
49814 // branched to use + in gecko and [].join() in others
49816 body = "tpl.compiled = function(values, parent){ return '" +
49817 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
49820 body = ["tpl.compiled = function(values, parent){ return ['"];
49821 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
49822 body.push("'].join('');};");
49823 body = body.join('');
49825 /** eval:var:zzzzzzz */
49830 applyTemplate : function(values){
49831 return this.master.compiled.call(this, values, {});
49835 apply : function(){
49836 return this.applyTemplate.apply(this, arguments);
49839 compile : function(){return this;}
49842 Roo.XTemplate.from = function(el){
49843 el = Roo.getDom(el);
49844 return new Roo.XTemplate(el.value || el.innerHTML);
49846 * Original code for Roojs - LGPL
49847 * <script type="text/javascript">
49851 * @class Roo.XComponent
49852 * A delayed Element creator...
49854 * Mypart.xyx = new Roo.XComponent({
49856 parent : 'Mypart.xyz', // empty == document.element.!!
49860 disabled : function() {}
49862 tree : function() { // return an tree of xtype declared components
49866 xtype : 'NestedLayoutPanel',
49871 * @extends Roo.util.Observable
49873 * @param cfg {Object} configuration of component
49876 Roo.XComponent = function(cfg) {
49877 Roo.apply(this, cfg);
49881 * Fires when this the componnt is built
49882 * @param {Roo.XComponent} c the component
49886 * @event buildcomplete
49887 * Fires on the top level element when all elements have been built
49888 * @param {Roo.XComponent} c the top level component.
49890 'buildcomplete' : true,
49894 Roo.XComponent.register(this);
49895 this.modules = false;
49896 this.el = false; // where the layout goes..
49900 Roo.extend(Roo.XComponent, Roo.util.Observable, {
49903 * The created element (with Roo.factory())
49904 * @type {Roo.Layout}
49910 * for BC - use el in new code
49911 * @type {Roo.Layout}
49917 * for BC - use el in new code
49918 * @type {Roo.Layout}
49923 * @cfg {Function|boolean} disabled
49924 * If this module is disabled by some rule, return true from the funtion
49929 * @cfg {String} parent
49930 * Name of parent element which it get xtype added to..
49935 * @cfg {String} order
49936 * Used to set the order in which elements are created (usefull for multiple tabs)
49941 * @cfg {String} name
49942 * String to display while loading.
49946 * @cfg {Array} items
49947 * A single item array - the first element is the root of the tree..
49948 * It's done this way to stay compatible with the Xtype system...
49956 Roo.apply(Roo.XComponent, {
49959 * @property buildCompleted
49960 * True when the builder has completed building the interface.
49963 buildCompleted : false,
49966 * @property topModule
49967 * the upper most module - uses document.element as it's constructor.
49974 * @property modules
49975 * array of modules to be created by registration system.
49976 * @type Roo.XComponent
49983 * Register components to be built later.
49985 * This solves the following issues
49986 * - Building is not done on page load, but after an authentication process has occured.
49987 * - Interface elements are registered on page load
49988 * - Parent Interface elements may not be loaded before child, so this handles that..
49995 module : 'Pman.Tab.projectMgr',
49997 parent : 'Pman.layout',
49998 disabled : false, // or use a function..
50001 * * @param {Object} details about module
50003 register : function(obj) {
50004 this.modules.push(obj);
50008 * convert a string to an object..
50012 toObject : function(str)
50014 if (!str || typeof(str) == 'object') {
50017 var ar = str.split('.');
50021 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
50023 throw "Module not found : " + str;
50025 Roo.each(ar, function(e) {
50026 if (typeof(o[e]) == 'undefined') {
50027 throw "Module not found : " + str;
50037 * move modules into their correct place in the tree..
50040 preBuild : function ()
50043 Roo.each(this.modules , function (obj)
50045 obj.parent = this.toObject(obj.parent);
50048 this.topModule = obj;
50052 if (!obj.parent.modules) {
50053 obj.parent.modules = new Roo.util.MixedCollection(false,
50054 function(o) { return o.order + '' }
50058 obj.parent.modules.add(obj);
50063 * make a list of modules to build.
50064 * @return {Array} list of modules.
50067 buildOrder : function()
50070 var cmp = function(a,b) {
50071 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
50074 if (!this.topModule || !this.topModule.modules) {
50075 throw "No top level modules to build";
50078 // make a flat list in order of modules to build.
50079 var mods = [ this.topModule ];
50082 // add modules to their parents..
50083 var addMod = function(m) {
50084 // console.log(m.modKey);
50088 m.modules.keySort('ASC', cmp );
50089 m.modules.each(addMod);
50091 // not sure if this is used any more..
50093 m.finalize.name = m.name + " (clean up) ";
50094 mods.push(m.finalize);
50098 this.topModule.modules.keySort('ASC', cmp );
50099 this.topModule.modules.each(addMod);
50104 * Build the registered modules.
50105 * @param {Object} parent element.
50106 * @param {Function} optional method to call after module has been added.
50114 var mods = this.buildOrder();
50116 //this.allmods = mods;
50117 //console.log(mods);
50119 if (!mods.length) { // should not happen
50120 throw "NO modules!!!";
50125 // flash it up as modal - so we store the mask!?
50126 Roo.MessageBox.show({ title: 'loading' });
50127 Roo.MessageBox.show({
50128 title: "Please wait...",
50129 msg: "Building Interface...",
50136 var total = mods.length;
50139 var progressRun = function() {
50140 if (!mods.length) {
50141 console.log('hide?');
50142 Roo.MessageBox.hide();
50143 _this.topModule.fireEvent('buildcomplete', _this.topModule);
50147 var m = mods.shift();
50149 if (typeof(m) == 'function') { // not sure if this is supported any more..
50151 return progressRun.defer(10, _this);
50154 Roo.MessageBox.updateProgress(
50155 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
50157 (m.name ? (' - ' + m.name) : '')
50162 var disabled = (typeof(m.disabled) == 'function') ?
50163 m.disabled.call(m.module.disabled) : m.disabled;
50167 return progressRun(); // we do not update the display!
50171 // it's a top level one..
50172 var layoutbase = new Ext.BorderLayout(document.body, {
50178 tabPosition: 'top',
50179 //resizeTabs: true,
50180 alwaysShowTabs: true,
50184 var tree = m.tree();
50185 tree.region = 'center';
50186 m.el = layoutbase.addxtype(tree);
50188 m.layout = m.panel.layout;
50189 return progressRun.defer(10, _this);
50192 var tree = m.tree();
50193 tree.region = tree.region || m.region;
50194 m.el = m.parent.el.addxtype(tree);
50195 m.fireEvent('built', m);
50197 m.layout = m.panel.layout;
50198 progressRun.defer(10, _this);
50201 progressRun.defer(1, _this);
50211 //<script type="text/javascript">
50216 * @extends Roo.LayoutDialog
50217 * A generic Login Dialog..... - only one needed in theory!?!?
50219 * Fires XComponent builder on success...
50222 * username,password, lang = for login actions.
50223 * check = 1 for periodic checking that sesion is valid.
50224 * passwordRequest = email request password
50225 * logout = 1 = to logout
50227 * Affects: (this id="????" elements)
50228 * loading (removed) (used to indicate application is loading)
50229 * loading-mask (hides) (used to hide application when it's building loading)
50235 * Myapp.login = Roo.Login({
50251 Roo.Login = function(cfg)
50254 'refreshed' : true,
50257 Roo.apply(this,cfg);
50259 Roo.onReady(function() {
50265 Roo.Login.superclass.constructor.call(this, this);
50266 //this.addxtype(this.items[0]);
50272 Roo.extend(Roo.Login, Roo.LayoutDialog, {
50275 * @cfg {String} method
50276 * Method used to query for login details.
50281 * @cfg {String} url
50282 * URL to query login data. - eg. baseURL + '/Login.php'
50288 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
50293 * @property checkFails
50294 * Number of times we have attempted to get authentication check, and failed.
50299 * @property intervalID
50300 * The window interval that does the constant login checking.
50306 onLoad : function() // called on page load...
50310 if (Roo.get('loading')) { // clear any loading indicator..
50311 Roo.get('loading').remove();
50314 //this.switchLang('en'); // set the language to english..
50317 success: function(response, opts) { // check successfull...
50319 var res = this.processResponse(response);
50320 this.checkFails =0;
50321 if (!res.success) { // error!
50322 this.checkFails = 5;
50323 //console.log('call failure');
50324 return this.failure(response,opts);
50327 if (!res.data.id) { // id=0 == login failure.
50328 return this.show();
50332 //console.log(success);
50333 this.fillAuth(res.data);
50334 this.checkFails =0;
50335 Roo.XComponent.build();
50337 failure : this.show
50343 check: function(cfg) // called every so often to refresh cookie etc..
50345 if (cfg.again) { // could be undefined..
50348 this.checkFails = 0;
50351 if (this.sending) {
50352 if ( this.checkFails > 4) {
50353 Roo.MessageBox.alert("Error",
50354 "Error getting authentication status. - try reloading, or wait a while", function() {
50355 _this.sending = false;
50360 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
50363 this.sending = true;
50370 method: this.method,
50371 success: cfg.success || this.success,
50372 failure : cfg.failure || this.failure,
50382 window.onbeforeunload = function() { }; // false does not work for IE..
50392 failure : function() {
50393 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
50394 document.location = document.location.toString() + '?ts=' + Math.random();
50398 success : function() {
50399 _this.user = false;
50400 this.checkFails =0;
50402 document.location = document.location.toString() + '?ts=' + Math.random();
50409 processResponse : function (response)
50413 res = Roo.decode(response.responseText);
50415 if (typeof(res) != 'object') {
50416 res = { success : false, errorMsg : res, errors : true };
50418 if (typeof(res.success) == 'undefined') {
50419 res.success = false;
50423 res = { success : false, errorMsg : response.responseText, errors : true };
50428 success : function(response, opts) // check successfull...
50430 this.sending = false;
50431 var res = this.processResponse(response);
50432 if (!res.success) {
50433 return this.failure(response, opts);
50435 if (!res.data || !res.data.id) {
50436 return this.failure(response,opts);
50438 //console.log(res);
50439 this.fillAuth(res.data);
50441 this.checkFails =0;
50446 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
50448 this.authUser = -1;
50449 this.sending = false;
50450 var res = this.processResponse(response);
50451 //console.log(res);
50452 if ( this.checkFails > 2) {
50454 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
50455 "Error getting authentication status. - try reloading");
50458 opts.callCfg.again = true;
50459 this.check.defer(1000, this, [ opts.callCfg ]);
50465 fillAuth: function(au) {
50466 this.startAuthCheck();
50467 this.authUserId = au.id;
50468 this.authUser = au;
50469 this.lastChecked = new Date();
50470 this.fireEvent('refreshed', au);
50471 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
50472 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
50473 au.lang = au.lang || 'en';
50474 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
50475 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
50476 this.switchLang(au.lang );
50479 // open system... - -on setyp..
50480 if (this.authUserId < 0) {
50481 Roo.MessageBox.alert("Warning",
50482 "This is an open system - please set up a admin user with a password.");
50485 //Pman.onload(); // which should do nothing if it's a re-auth result...
50490 startAuthCheck : function() // starter for timeout checking..
50492 if (this.intervalID) { // timer already in place...
50496 this.intervalID = window.setInterval(function() {
50497 _this.check(false);
50498 }, 120000); // every 120 secs = 2mins..
50504 switchLang : function (lang)
50506 _T = typeof(_T) == 'undefined' ? false : _T;
50507 if (!_T || !lang.length) {
50511 if (!_T && lang != 'en') {
50512 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
50516 if (typeof(_T.en) == 'undefined') {
50518 Roo.apply(_T.en, _T);
50521 if (typeof(_T[lang]) == 'undefined') {
50522 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
50527 Roo.apply(_T, _T[lang]);
50528 // just need to set the text values for everything...
50530 /* this will not work ...
50534 function formLabel(name, val) {
50535 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
50538 formLabel('password', "Password"+':');
50539 formLabel('username', "Email Address"+':');
50540 formLabel('lang', "Language"+':');
50541 this.dialog.setTitle("Login");
50542 this.dialog.buttons[0].setText("Forgot Password");
50543 this.dialog.buttons[1].setText("Login");
50562 collapsible: false,
50564 center: { // needed??
50567 // tabPosition: 'top',
50570 alwaysShowTabs: false
50574 show : function(dlg)
50576 //console.log(this);
50577 this.form = this.layout.getRegion('center').activePanel.form;
50578 this.form.dialog = dlg;
50579 this.buttons[0].form = this.form;
50580 this.buttons[0].dialog = dlg
50581 this.buttons[1].form = this.form;
50582 this.buttons[1].dialog = dlg;
50584 //this.resizeToLogo.defer(1000,this);
50585 // this is all related to resizing for logos..
50586 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
50588 // this.resizeToLogo.defer(1000,this);
50591 //var w = Ext.lib.Dom.getViewWidth() - 100;
50592 //var h = Ext.lib.Dom.getViewHeight() - 100;
50593 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
50595 if (this.disabled) {
50600 if (this.user.id < 0) { // used for inital setup situations.
50604 if (this.intervalID) {
50605 // remove the timer
50606 window.clearInterval(this.intervalID);
50607 this.intervalID = false;
50611 if (Roo.get('loading')) {
50612 Roo.get('loading').remove();
50614 if (Roo.get('loading-mask')) {
50615 Roo.get('loading-mask').hide();
50618 //incomming._node = tnode;
50620 //this.dialog.modal = !modal;
50621 //this.dialog.show();
50625 this.form.setValues({
50626 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
50627 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
50630 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
50631 if (this.form.findField('username').getValue().length > 0 ){
50632 this.form.findField('password').focus();
50634 this.form.findField('username').focus();
50642 xtype : 'ContentPanel',
50654 style : 'margin: 10px;',
50657 actionfailed : function(f, act) {
50658 // form can return { errors: .... }
50660 //act.result.errors // invalid form element list...
50661 //act.result.errorMsg// invalid form element list...
50663 this.dialog.el.unmask();
50664 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
50665 "Login failed - communication error - try again.");
50668 actioncomplete: function(re, act) {
50670 Roo.state.Manager.set(
50671 this.dialog.realm + '.username',
50672 this.findField('username').getValue()
50674 Roo.state.Manager.set(
50675 this.dialog.realm + '.lang',
50676 this.findField('lang').getValue()
50679 this.dialog.fillAuth(act.result.data);
50681 this.dialog.hide();
50683 if (Roo.get('loading-mask')) {
50684 Roo.get('loading-mask').show();
50686 Roo.XComponent.build();
50694 xtype : 'TextField',
50696 fieldLabel: "Email Address",
50699 autoCreate : {tag: "input", type: "text", size: "20"}
50702 xtype : 'TextField',
50704 fieldLabel: "Password",
50705 inputType: 'password',
50708 autoCreate : {tag: "input", type: "text", size: "20"},
50710 specialkey : function(e,ev) {
50711 if (ev.keyCode == 13) {
50712 this.form.dialog.el.mask("Logging in");
50713 this.form.doAction('submit', {
50714 url: this.form.dialog.url,
50715 method: this.form.dialog.method,
50722 xtype : 'ComboBox',
50724 fieldLabel: "Language",
50727 xtype : 'SimpleStore',
50728 fields: ['lang', 'ldisp'],
50730 [ 'en', 'English' ],
50731 [ 'zh_HK' , '\u7E41\u4E2D' ],
50732 [ 'zh_CN', '\u7C21\u4E2D' ]
50736 valueField : 'lang',
50737 hiddenName: 'lang',
50739 displayField:'ldisp',
50743 triggerAction: 'all',
50744 emptyText:'Select a Language...',
50745 selectOnFocus:true,
50747 select : function(cb, rec, ix) {
50748 this.form.switchLang(rec.data.lang);
50764 text : "Forgot Password",
50766 click : function() {
50767 //console.log(this);
50768 var n = this.form.findField('username').getValue();
50770 Roo.MessageBox.alert("Error", "Fill in your email address");
50774 url: this.dialog.url,
50778 method: this.dialog.method,
50779 success: function(response, opts) { // check successfull...
50781 var res = this.dialog.processResponse(response);
50782 if (!res.success) { // error!
50783 Roo.MessageBox.alert("Error" ,
50784 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
50787 Roo.MessageBox.alert("Notice" ,
50788 "Please check you email for the Password Reset message");
50790 failure : function() {
50791 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
50804 click : function () {
50806 this.dialog.el.mask("Logging in");
50807 this.form.doAction('submit', {
50808 url: this.dialog.url,
50809 method: this.dialog.method