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);
4470 * Sets the HTML used as the template and optionally compiles it.
4471 * @param {String} html
4472 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4473 * @return {Roo.Template} this
4475 set : function(html, compile){
4477 this.compiled = null;
4485 * True to disable format functions (defaults to false)
4488 disableFormats : false,
4491 * The regular expression used to match template variables
4495 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4498 * Compiles the template into an internal function, eliminating the RegEx overhead.
4499 * @return {Roo.Template} this
4501 compile : function(){
4502 var fm = Roo.util.Format;
4503 var useF = this.disableFormats !== true;
4504 var sep = Roo.isGecko ? "+" : ",";
4505 var fn = function(m, name, format, args){
4507 args = args ? ',' + args : "";
4508 if(format.substr(0, 5) != "this."){
4509 format = "fm." + format + '(';
4511 format = 'this.call("'+ format.substr(5) + '", ';
4515 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4517 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4520 // branched to use + in gecko and [].join() in others
4522 body = "this.compiled = function(values){ return '" +
4523 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4526 body = ["this.compiled = function(values){ return ['"];
4527 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4528 body.push("'].join('');};");
4529 body = body.join('');
4539 // private function used to call members
4540 call : function(fnName, value, allValues){
4541 return this[fnName](value, allValues);
4545 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4546 * @param {String/HTMLElement/Roo.Element} el The context element
4547 * @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'})
4548 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4549 * @return {HTMLElement/Roo.Element} The new node or Element
4551 insertFirst: function(el, values, returnElement){
4552 return this.doInsert('afterBegin', el, values, returnElement);
4556 * Applies the supplied values to the template and inserts the new node(s) before el.
4557 * @param {String/HTMLElement/Roo.Element} el The context element
4558 * @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'})
4559 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4560 * @return {HTMLElement/Roo.Element} The new node or Element
4562 insertBefore: function(el, values, returnElement){
4563 return this.doInsert('beforeBegin', el, values, returnElement);
4567 * Applies the supplied values to the template and inserts the new node(s) after el.
4568 * @param {String/HTMLElement/Roo.Element} el The context element
4569 * @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'})
4570 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4571 * @return {HTMLElement/Roo.Element} The new node or Element
4573 insertAfter : function(el, values, returnElement){
4574 return this.doInsert('afterEnd', el, values, returnElement);
4578 * Applies the supplied values to the template and appends the new node(s) to el.
4579 * @param {String/HTMLElement/Roo.Element} el The context element
4580 * @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'})
4581 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4582 * @return {HTMLElement/Roo.Element} The new node or Element
4584 append : function(el, values, returnElement){
4585 return this.doInsert('beforeEnd', el, values, returnElement);
4588 doInsert : function(where, el, values, returnEl){
4589 el = Roo.getDom(el);
4590 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4591 return returnEl ? Roo.get(newNode, true) : newNode;
4595 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4596 * @param {String/HTMLElement/Roo.Element} el The context element
4597 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4598 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4599 * @return {HTMLElement/Roo.Element} The new node or Element
4601 overwrite : function(el, values, returnElement){
4602 el = Roo.getDom(el);
4603 el.innerHTML = this.applyTemplate(values);
4604 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4608 * Alias for {@link #applyTemplate}
4611 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4614 Roo.DomHelper.Template = Roo.Template;
4617 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4618 * @param {String/HTMLElement} el A DOM element or its id
4619 * @returns {Roo.Template} The created template
4622 Roo.Template.from = function(el){
4623 el = Roo.getDom(el);
4624 return new Roo.Template(el.value || el.innerHTML);
4627 * Ext JS Library 1.1.1
4628 * Copyright(c) 2006-2007, Ext JS, LLC.
4630 * Originally Released Under LGPL - original licence link has changed is not relivant.
4633 * <script type="text/javascript">
4638 * This is code is also distributed under MIT license for use
4639 * with jQuery and prototype JavaScript libraries.
4642 * @class Roo.DomQuery
4643 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).
4645 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>
4648 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.
4650 <h4>Element Selectors:</h4>
4652 <li> <b>*</b> any element</li>
4653 <li> <b>E</b> an element with the tag E</li>
4654 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4655 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4656 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4657 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4659 <h4>Attribute Selectors:</h4>
4660 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4662 <li> <b>E[foo]</b> has an attribute "foo"</li>
4663 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4664 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4665 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4666 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4667 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4668 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4670 <h4>Pseudo Classes:</h4>
4672 <li> <b>E:first-child</b> E is the first child of its parent</li>
4673 <li> <b>E:last-child</b> E is the last child of its parent</li>
4674 <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>
4675 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4676 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4677 <li> <b>E:only-child</b> E is the only child of its parent</li>
4678 <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>
4679 <li> <b>E:first</b> the first E in the resultset</li>
4680 <li> <b>E:last</b> the last E in the resultset</li>
4681 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4682 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4683 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4684 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4685 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4686 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4687 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4688 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4689 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4691 <h4>CSS Value Selectors:</h4>
4693 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4694 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4695 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4696 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4697 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4698 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4702 Roo.DomQuery = function(){
4703 var cache = {}, simpleCache = {}, valueCache = {};
4704 var nonSpace = /\S/;
4705 var trimRe = /^\s+|\s+$/g;
4706 var tplRe = /\{(\d+)\}/g;
4707 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4708 var tagTokenRe = /^(#)?([\w-\*]+)/;
4709 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4711 function child(p, index){
4713 var n = p.firstChild;
4715 if(n.nodeType == 1){
4726 while((n = n.nextSibling) && n.nodeType != 1);
4731 while((n = n.previousSibling) && n.nodeType != 1);
4735 function children(d){
4736 var n = d.firstChild, ni = -1;
4738 var nx = n.nextSibling;
4739 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4749 function byClassName(c, a, v){
4753 var r = [], ri = -1, cn;
4754 for(var i = 0, ci; ci = c[i]; i++){
4755 if((' '+ci.className+' ').indexOf(v) != -1){
4762 function attrValue(n, attr){
4763 if(!n.tagName && typeof n.length != "undefined"){
4772 if(attr == "class" || attr == "className"){
4775 return n.getAttribute(attr) || n[attr];
4779 function getNodes(ns, mode, tagName){
4780 var result = [], ri = -1, cs;
4784 tagName = tagName || "*";
4785 if(typeof ns.getElementsByTagName != "undefined"){
4789 for(var i = 0, ni; ni = ns[i]; i++){
4790 cs = ni.getElementsByTagName(tagName);
4791 for(var j = 0, ci; ci = cs[j]; j++){
4795 }else if(mode == "/" || mode == ">"){
4796 var utag = tagName.toUpperCase();
4797 for(var i = 0, ni, cn; ni = ns[i]; i++){
4798 cn = ni.children || ni.childNodes;
4799 for(var j = 0, cj; cj = cn[j]; j++){
4800 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4805 }else if(mode == "+"){
4806 var utag = tagName.toUpperCase();
4807 for(var i = 0, n; n = ns[i]; i++){
4808 while((n = n.nextSibling) && n.nodeType != 1);
4809 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4813 }else if(mode == "~"){
4814 for(var i = 0, n; n = ns[i]; i++){
4815 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4824 function concat(a, b){
4828 for(var i = 0, l = b.length; i < l; i++){
4834 function byTag(cs, tagName){
4835 if(cs.tagName || cs == document){
4841 var r = [], ri = -1;
4842 tagName = tagName.toLowerCase();
4843 for(var i = 0, ci; ci = cs[i]; i++){
4844 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4851 function byId(cs, attr, id){
4852 if(cs.tagName || cs == document){
4858 var r = [], ri = -1;
4859 for(var i = 0,ci; ci = cs[i]; i++){
4860 if(ci && ci.id == id){
4868 function byAttribute(cs, attr, value, op, custom){
4869 var r = [], ri = -1, st = custom=="{";
4870 var f = Roo.DomQuery.operators[op];
4871 for(var i = 0, ci; ci = cs[i]; i++){
4874 a = Roo.DomQuery.getStyle(ci, attr);
4876 else if(attr == "class" || attr == "className"){
4878 }else if(attr == "for"){
4880 }else if(attr == "href"){
4881 a = ci.getAttribute("href", 2);
4883 a = ci.getAttribute(attr);
4885 if((f && f(a, value)) || (!f && a)){
4892 function byPseudo(cs, name, value){
4893 return Roo.DomQuery.pseudos[name](cs, value);
4896 // This is for IE MSXML which does not support expandos.
4897 // IE runs the same speed using setAttribute, however FF slows way down
4898 // and Safari completely fails so they need to continue to use expandos.
4899 var isIE = window.ActiveXObject ? true : false;
4901 // this eval is stop the compressor from
4902 // renaming the variable to something shorter
4904 /** eval:var:batch */
4909 function nodupIEXml(cs){
4911 cs[0].setAttribute("_nodup", d);
4913 for(var i = 1, len = cs.length; i < len; i++){
4915 if(!c.getAttribute("_nodup") != d){
4916 c.setAttribute("_nodup", d);
4920 for(var i = 0, len = cs.length; i < len; i++){
4921 cs[i].removeAttribute("_nodup");
4930 var len = cs.length, c, i, r = cs, cj, ri = -1;
4931 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4934 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4935 return nodupIEXml(cs);
4939 for(i = 1; c = cs[i]; i++){
4944 for(var j = 0; j < i; j++){
4947 for(j = i+1; cj = cs[j]; j++){
4959 function quickDiffIEXml(c1, c2){
4961 for(var i = 0, len = c1.length; i < len; i++){
4962 c1[i].setAttribute("_qdiff", d);
4965 for(var i = 0, len = c2.length; i < len; i++){
4966 if(c2[i].getAttribute("_qdiff") != d){
4967 r[r.length] = c2[i];
4970 for(var i = 0, len = c1.length; i < len; i++){
4971 c1[i].removeAttribute("_qdiff");
4976 function quickDiff(c1, c2){
4977 var len1 = c1.length;
4981 if(isIE && c1[0].selectSingleNode){
4982 return quickDiffIEXml(c1, c2);
4985 for(var i = 0; i < len1; i++){
4989 for(var i = 0, len = c2.length; i < len; i++){
4990 if(c2[i]._qdiff != d){
4991 r[r.length] = c2[i];
4997 function quickId(ns, mode, root, id){
4999 var d = root.ownerDocument || root;
5000 return d.getElementById(id);
5002 ns = getNodes(ns, mode, "*");
5003 return byId(ns, null, id);
5007 getStyle : function(el, name){
5008 return Roo.fly(el).getStyle(name);
5011 * Compiles a selector/xpath query into a reusable function. The returned function
5012 * takes one parameter "root" (optional), which is the context node from where the query should start.
5013 * @param {String} selector The selector/xpath query
5014 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5015 * @return {Function}
5017 compile : function(path, type){
5018 type = type || "select";
5020 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5021 var q = path, mode, lq;
5022 var tk = Roo.DomQuery.matchers;
5023 var tklen = tk.length;
5026 // accept leading mode switch
5027 var lmode = q.match(modeRe);
5028 if(lmode && lmode[1]){
5029 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5030 q = q.replace(lmode[1], "");
5032 // strip leading slashes
5033 while(path.substr(0, 1)=="/"){
5034 path = path.substr(1);
5037 while(q && lq != q){
5039 var tm = q.match(tagTokenRe);
5040 if(type == "select"){
5043 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5045 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5047 q = q.replace(tm[0], "");
5048 }else if(q.substr(0, 1) != '@'){
5049 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5054 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5056 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5058 q = q.replace(tm[0], "");
5061 while(!(mm = q.match(modeRe))){
5062 var matched = false;
5063 for(var j = 0; j < tklen; j++){
5065 var m = q.match(t.re);
5067 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5070 q = q.replace(m[0], "");
5075 // prevent infinite loop on bad selector
5077 throw 'Error parsing selector, parsing failed at "' + q + '"';
5081 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5082 q = q.replace(mm[1], "");
5085 fn[fn.length] = "return nodup(n);\n}";
5088 * list of variables that need from compression as they are used by eval.
5098 * eval:var:byClassName
5100 * eval:var:byAttribute
5101 * eval:var:attrValue
5109 * Selects a group of elements.
5110 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5111 * @param {Node} root (optional) The start of the query (defaults to document).
5114 select : function(path, root, type){
5115 if(!root || root == document){
5118 if(typeof root == "string"){
5119 root = document.getElementById(root);
5121 var paths = path.split(",");
5123 for(var i = 0, len = paths.length; i < len; i++){
5124 var p = paths[i].replace(trimRe, "");
5126 cache[p] = Roo.DomQuery.compile(p);
5128 throw p + " is not a valid selector";
5131 var result = cache[p](root);
5132 if(result && result != document){
5133 results = results.concat(result);
5136 if(paths.length > 1){
5137 return nodup(results);
5143 * Selects a single element.
5144 * @param {String} selector The selector/xpath query
5145 * @param {Node} root (optional) The start of the query (defaults to document).
5148 selectNode : function(path, root){
5149 return Roo.DomQuery.select(path, root)[0];
5153 * Selects the value of a node, optionally replacing null with the defaultValue.
5154 * @param {String} selector The selector/xpath query
5155 * @param {Node} root (optional) The start of the query (defaults to document).
5156 * @param {String} defaultValue
5158 selectValue : function(path, root, defaultValue){
5159 path = path.replace(trimRe, "");
5160 if(!valueCache[path]){
5161 valueCache[path] = Roo.DomQuery.compile(path, "select");
5163 var n = valueCache[path](root);
5164 n = n[0] ? n[0] : n;
5165 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5166 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5170 * Selects the value of a node, parsing integers and floats.
5171 * @param {String} selector The selector/xpath query
5172 * @param {Node} root (optional) The start of the query (defaults to document).
5173 * @param {Number} defaultValue
5176 selectNumber : function(path, root, defaultValue){
5177 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5178 return parseFloat(v);
5182 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5183 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5184 * @param {String} selector The simple selector to test
5187 is : function(el, ss){
5188 if(typeof el == "string"){
5189 el = document.getElementById(el);
5191 var isArray = (el instanceof Array);
5192 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5193 return isArray ? (result.length == el.length) : (result.length > 0);
5197 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5198 * @param {Array} el An array of elements to filter
5199 * @param {String} selector The simple selector to test
5200 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5201 * the selector instead of the ones that match
5204 filter : function(els, ss, nonMatches){
5205 ss = ss.replace(trimRe, "");
5206 if(!simpleCache[ss]){
5207 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5209 var result = simpleCache[ss](els);
5210 return nonMatches ? quickDiff(result, els) : result;
5214 * Collection of matching regular expressions and code snippets.
5218 select: 'n = byClassName(n, null, " {1} ");'
5220 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5221 select: 'n = byPseudo(n, "{1}", "{2}");'
5223 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5224 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5227 select: 'n = byId(n, null, "{1}");'
5230 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5235 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5236 * 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, > <.
5239 "=" : function(a, v){
5242 "!=" : function(a, v){
5245 "^=" : function(a, v){
5246 return a && a.substr(0, v.length) == v;
5248 "$=" : function(a, v){
5249 return a && a.substr(a.length-v.length) == v;
5251 "*=" : function(a, v){
5252 return a && a.indexOf(v) !== -1;
5254 "%=" : function(a, v){
5255 return (a % v) == 0;
5257 "|=" : function(a, v){
5258 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5260 "~=" : function(a, v){
5261 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5266 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5267 * and the argument (if any) supplied in the selector.
5270 "first-child" : function(c){
5271 var r = [], ri = -1, n;
5272 for(var i = 0, ci; ci = n = c[i]; i++){
5273 while((n = n.previousSibling) && n.nodeType != 1);
5281 "last-child" : function(c){
5282 var r = [], ri = -1, n;
5283 for(var i = 0, ci; ci = n = c[i]; i++){
5284 while((n = n.nextSibling) && n.nodeType != 1);
5292 "nth-child" : function(c, a) {
5293 var r = [], ri = -1;
5294 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5295 var f = (m[1] || 1) - 0, l = m[2] - 0;
5296 for(var i = 0, n; n = c[i]; i++){
5297 var pn = n.parentNode;
5298 if (batch != pn._batch) {
5300 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5301 if(cn.nodeType == 1){
5308 if (l == 0 || n.nodeIndex == l){
5311 } else if ((n.nodeIndex + l) % f == 0){
5319 "only-child" : function(c){
5320 var r = [], ri = -1;;
5321 for(var i = 0, ci; ci = c[i]; i++){
5322 if(!prev(ci) && !next(ci)){
5329 "empty" : function(c){
5330 var r = [], ri = -1;
5331 for(var i = 0, ci; ci = c[i]; i++){
5332 var cns = ci.childNodes, j = 0, cn, empty = true;
5335 if(cn.nodeType == 1 || cn.nodeType == 3){
5347 "contains" : function(c, v){
5348 var r = [], ri = -1;
5349 for(var i = 0, ci; ci = c[i]; i++){
5350 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5357 "nodeValue" : function(c, v){
5358 var r = [], ri = -1;
5359 for(var i = 0, ci; ci = c[i]; i++){
5360 if(ci.firstChild && ci.firstChild.nodeValue == v){
5367 "checked" : function(c){
5368 var r = [], ri = -1;
5369 for(var i = 0, ci; ci = c[i]; i++){
5370 if(ci.checked == true){
5377 "not" : function(c, ss){
5378 return Roo.DomQuery.filter(c, ss, true);
5381 "odd" : function(c){
5382 return this["nth-child"](c, "odd");
5385 "even" : function(c){
5386 return this["nth-child"](c, "even");
5389 "nth" : function(c, a){
5390 return c[a-1] || [];
5393 "first" : function(c){
5397 "last" : function(c){
5398 return c[c.length-1] || [];
5401 "has" : function(c, ss){
5402 var s = Roo.DomQuery.select;
5403 var r = [], ri = -1;
5404 for(var i = 0, ci; ci = c[i]; i++){
5405 if(s(ss, ci).length > 0){
5412 "next" : function(c, ss){
5413 var is = Roo.DomQuery.is;
5414 var r = [], ri = -1;
5415 for(var i = 0, ci; ci = c[i]; i++){
5424 "prev" : function(c, ss){
5425 var is = Roo.DomQuery.is;
5426 var r = [], ri = -1;
5427 for(var i = 0, ci; ci = c[i]; i++){
5440 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5441 * @param {String} path The selector/xpath query
5442 * @param {Node} root (optional) The start of the query (defaults to document).
5447 Roo.query = Roo.DomQuery.select;
5450 * Ext JS Library 1.1.1
5451 * Copyright(c) 2006-2007, Ext JS, LLC.
5453 * Originally Released Under LGPL - original licence link has changed is not relivant.
5456 * <script type="text/javascript">
5460 * @class Roo.util.Observable
5461 * Base class that provides a common interface for publishing events. Subclasses are expected to
5462 * to have a property "events" with all the events defined.<br>
5465 Employee = function(name){
5472 Roo.extend(Employee, Roo.util.Observable);
5474 * @param {Object} config properties to use (incuding events / listeners)
5477 Roo.util.Observable = function(cfg){
5480 this.addEvents(cfg.events || {});
5482 delete cfg.events; // make sure
5485 Roo.apply(this, cfg);
5488 this.on(this.listeners);
5489 delete this.listeners;
5492 Roo.util.Observable.prototype = {
5494 * @cfg {Object} listeners list of events and functions to call for this object,
5498 'click' : function(e) {
5508 * Fires the specified event with the passed parameters (minus the event name).
5509 * @param {String} eventName
5510 * @param {Object...} args Variable number of parameters are passed to handlers
5511 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5513 fireEvent : function(){
5514 var ce = this.events[arguments[0].toLowerCase()];
5515 if(typeof ce == "object"){
5516 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5523 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5526 * Appends an event handler to this component
5527 * @param {String} eventName The type of event to listen for
5528 * @param {Function} handler The method the event invokes
5529 * @param {Object} scope (optional) The scope in which to execute the handler
5530 * function. The handler function's "this" context.
5531 * @param {Object} options (optional) An object containing handler configuration
5532 * properties. This may contain any of the following properties:<ul>
5533 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5534 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5535 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5536 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5537 * by the specified number of milliseconds. If the event fires again within that time, the original
5538 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5541 * <b>Combining Options</b><br>
5542 * Using the options argument, it is possible to combine different types of listeners:<br>
5544 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5546 el.on('click', this.onClick, this, {
5553 * <b>Attaching multiple handlers in 1 call</b><br>
5554 * The method also allows for a single argument to be passed which is a config object containing properties
5555 * which specify multiple handlers.
5564 fn: this.onMouseOver,
5568 fn: this.onMouseOut,
5574 * Or a shorthand syntax which passes the same scope object to all handlers:
5577 'click': this.onClick,
5578 'mouseover': this.onMouseOver,
5579 'mouseout': this.onMouseOut,
5584 addListener : function(eventName, fn, scope, o){
5585 if(typeof eventName == "object"){
5588 if(this.filterOptRe.test(e)){
5591 if(typeof o[e] == "function"){
5593 this.addListener(e, o[e], o.scope, o);
5595 // individual options
5596 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5601 o = (!o || typeof o == "boolean") ? {} : o;
5602 eventName = eventName.toLowerCase();
5603 var ce = this.events[eventName] || true;
5604 if(typeof ce == "boolean"){
5605 ce = new Roo.util.Event(this, eventName);
5606 this.events[eventName] = ce;
5608 ce.addListener(fn, scope, o);
5612 * Removes a listener
5613 * @param {String} eventName The type of event to listen for
5614 * @param {Function} handler The handler to remove
5615 * @param {Object} scope (optional) The scope (this object) for the handler
5617 removeListener : function(eventName, fn, scope){
5618 var ce = this.events[eventName.toLowerCase()];
5619 if(typeof ce == "object"){
5620 ce.removeListener(fn, scope);
5625 * Removes all listeners for this object
5627 purgeListeners : function(){
5628 for(var evt in this.events){
5629 if(typeof this.events[evt] == "object"){
5630 this.events[evt].clearListeners();
5635 relayEvents : function(o, events){
5636 var createHandler = function(ename){
5638 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5641 for(var i = 0, len = events.length; i < len; i++){
5642 var ename = events[i];
5643 if(!this.events[ename]){ this.events[ename] = true; };
5644 o.on(ename, createHandler(ename), this);
5649 * Used to define events on this Observable
5650 * @param {Object} object The object with the events defined
5652 addEvents : function(o){
5656 Roo.applyIf(this.events, o);
5660 * Checks to see if this object has any listeners for a specified event
5661 * @param {String} eventName The name of the event to check for
5662 * @return {Boolean} True if the event is being listened for, else false
5664 hasListener : function(eventName){
5665 var e = this.events[eventName];
5666 return typeof e == "object" && e.listeners.length > 0;
5670 * Appends an event handler to this element (shorthand for addListener)
5671 * @param {String} eventName The type of event to listen for
5672 * @param {Function} handler The method the event invokes
5673 * @param {Object} scope (optional) The scope in which to execute the handler
5674 * function. The handler function's "this" context.
5675 * @param {Object} options (optional)
5678 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5680 * Removes a listener (shorthand for removeListener)
5681 * @param {String} eventName The type of event to listen for
5682 * @param {Function} handler The handler to remove
5683 * @param {Object} scope (optional) The scope (this object) for the handler
5686 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5689 * Starts capture on the specified Observable. All events will be passed
5690 * to the supplied function with the event name + standard signature of the event
5691 * <b>before</b> the event is fired. If the supplied function returns false,
5692 * the event will not fire.
5693 * @param {Observable} o The Observable to capture
5694 * @param {Function} fn The function to call
5695 * @param {Object} scope (optional) The scope (this object) for the fn
5698 Roo.util.Observable.capture = function(o, fn, scope){
5699 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5703 * Removes <b>all</b> added captures from the Observable.
5704 * @param {Observable} o The Observable to release
5707 Roo.util.Observable.releaseCapture = function(o){
5708 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5713 var createBuffered = function(h, o, scope){
5714 var task = new Roo.util.DelayedTask();
5716 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5720 var createSingle = function(h, e, fn, scope){
5722 e.removeListener(fn, scope);
5723 return h.apply(scope, arguments);
5727 var createDelayed = function(h, o, scope){
5729 var args = Array.prototype.slice.call(arguments, 0);
5730 setTimeout(function(){
5731 h.apply(scope, args);
5736 Roo.util.Event = function(obj, name){
5739 this.listeners = [];
5742 Roo.util.Event.prototype = {
5743 addListener : function(fn, scope, options){
5744 var o = options || {};
5745 scope = scope || this.obj;
5746 if(!this.isListening(fn, scope)){
5747 var l = {fn: fn, scope: scope, options: o};
5750 h = createDelayed(h, o, scope);
5753 h = createSingle(h, this, fn, scope);
5756 h = createBuffered(h, o, scope);
5759 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5760 this.listeners.push(l);
5762 this.listeners = this.listeners.slice(0);
5763 this.listeners.push(l);
5768 findListener : function(fn, scope){
5769 scope = scope || this.obj;
5770 var ls = this.listeners;
5771 for(var i = 0, len = ls.length; i < len; i++){
5773 if(l.fn == fn && l.scope == scope){
5780 isListening : function(fn, scope){
5781 return this.findListener(fn, scope) != -1;
5784 removeListener : function(fn, scope){
5786 if((index = this.findListener(fn, scope)) != -1){
5788 this.listeners.splice(index, 1);
5790 this.listeners = this.listeners.slice(0);
5791 this.listeners.splice(index, 1);
5798 clearListeners : function(){
5799 this.listeners = [];
5803 var ls = this.listeners, scope, len = ls.length;
5806 var args = Array.prototype.slice.call(arguments, 0);
5807 for(var i = 0; i < len; i++){
5809 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5810 this.firing = false;
5814 this.firing = false;
5821 * Ext JS Library 1.1.1
5822 * Copyright(c) 2006-2007, Ext JS, LLC.
5824 * Originally Released Under LGPL - original licence link has changed is not relivant.
5827 * <script type="text/javascript">
5831 * @class Roo.EventManager
5832 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5833 * several useful events directly.
5834 * See {@link Roo.EventObject} for more details on normalized event objects.
5837 Roo.EventManager = function(){
5838 var docReadyEvent, docReadyProcId, docReadyState = false;
5839 var resizeEvent, resizeTask, textEvent, textSize;
5840 var E = Roo.lib.Event;
5841 var D = Roo.lib.Dom;
5844 var fireDocReady = function(){
5846 docReadyState = true;
5849 clearInterval(docReadyProcId);
5851 if(Roo.isGecko || Roo.isOpera) {
5852 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5855 var defer = document.getElementById("ie-deferred-loader");
5857 defer.onreadystatechange = null;
5858 defer.parentNode.removeChild(defer);
5862 docReadyEvent.fire();
5863 docReadyEvent.clearListeners();
5868 var initDocReady = function(){
5869 docReadyEvent = new Roo.util.Event();
5870 if(Roo.isGecko || Roo.isOpera) {
5871 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5873 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5874 var defer = document.getElementById("ie-deferred-loader");
5875 defer.onreadystatechange = function(){
5876 if(this.readyState == "complete"){
5880 }else if(Roo.isSafari){
5881 docReadyProcId = setInterval(function(){
5882 var rs = document.readyState;
5883 if(rs == "complete") {
5888 // no matter what, make sure it fires on load
5889 E.on(window, "load", fireDocReady);
5892 var createBuffered = function(h, o){
5893 var task = new Roo.util.DelayedTask(h);
5895 // create new event object impl so new events don't wipe out properties
5896 e = new Roo.EventObjectImpl(e);
5897 task.delay(o.buffer, h, null, [e]);
5901 var createSingle = function(h, el, ename, fn){
5903 Roo.EventManager.removeListener(el, ename, fn);
5908 var createDelayed = function(h, o){
5910 // create new event object impl so new events don't wipe out properties
5911 e = new Roo.EventObjectImpl(e);
5912 setTimeout(function(){
5918 var listen = function(element, ename, opt, fn, scope){
5919 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5920 fn = fn || o.fn; scope = scope || o.scope;
5921 var el = Roo.getDom(element);
5923 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5925 var h = function(e){
5926 e = Roo.EventObject.setEvent(e);
5929 t = e.getTarget(o.delegate, el);
5936 if(o.stopEvent === true){
5939 if(o.preventDefault === true){
5942 if(o.stopPropagation === true){
5943 e.stopPropagation();
5946 if(o.normalized === false){
5950 fn.call(scope || el, e, t, o);
5953 h = createDelayed(h, o);
5956 h = createSingle(h, el, ename, fn);
5959 h = createBuffered(h, o);
5961 fn._handlers = fn._handlers || [];
5962 fn._handlers.push([Roo.id(el), ename, h]);
5965 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5966 el.addEventListener("DOMMouseScroll", h, false);
5967 E.on(window, 'unload', function(){
5968 el.removeEventListener("DOMMouseScroll", h, false);
5971 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5972 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5977 var stopListening = function(el, ename, fn){
5978 var id = Roo.id(el), hds = fn._handlers, hd = fn;
5980 for(var i = 0, len = hds.length; i < len; i++){
5982 if(h[0] == id && h[1] == ename){
5989 E.un(el, ename, hd);
5990 el = Roo.getDom(el);
5991 if(ename == "mousewheel" && el.addEventListener){
5992 el.removeEventListener("DOMMouseScroll", hd, false);
5994 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5995 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5999 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6006 * @scope Roo.EventManager
6011 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6012 * object with a Roo.EventObject
6013 * @param {Function} fn The method the event invokes
6014 * @param {Object} scope An object that becomes the scope of the handler
6015 * @param {boolean} override If true, the obj passed in becomes
6016 * the execution scope of the listener
6017 * @return {Function} The wrapped function
6020 wrap : function(fn, scope, override){
6022 Roo.EventObject.setEvent(e);
6023 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6028 * Appends an event handler to an element (shorthand for addListener)
6029 * @param {String/HTMLElement} element The html element or id to assign the
6030 * @param {String} eventName The type of event to listen for
6031 * @param {Function} handler The method the event invokes
6032 * @param {Object} scope (optional) The scope in which to execute the handler
6033 * function. The handler function's "this" context.
6034 * @param {Object} options (optional) An object containing handler configuration
6035 * properties. This may contain any of the following properties:<ul>
6036 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6037 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6038 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6039 * <li>preventDefault {Boolean} True to prevent the default action</li>
6040 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6041 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6042 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6043 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6044 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6045 * by the specified number of milliseconds. If the event fires again within that time, the original
6046 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6049 * <b>Combining Options</b><br>
6050 * Using the options argument, it is possible to combine different types of listeners:<br>
6052 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6054 el.on('click', this.onClick, this, {
6061 * <b>Attaching multiple handlers in 1 call</b><br>
6062 * The method also allows for a single argument to be passed which is a config object containing properties
6063 * which specify multiple handlers.
6073 fn: this.onMouseOver
6082 * Or a shorthand syntax:<br>
6085 'click' : this.onClick,
6086 'mouseover' : this.onMouseOver,
6087 'mouseout' : this.onMouseOut
6091 addListener : function(element, eventName, fn, scope, options){
6092 if(typeof eventName == "object"){
6098 if(typeof o[e] == "function"){
6100 listen(element, e, o, o[e], o.scope);
6102 // individual options
6103 listen(element, e, o[e]);
6108 return listen(element, eventName, options, fn, scope);
6112 * Removes an event handler
6114 * @param {String/HTMLElement} element The id or html element to remove the
6116 * @param {String} eventName The type of event
6117 * @param {Function} fn
6118 * @return {Boolean} True if a listener was actually removed
6120 removeListener : function(element, eventName, fn){
6121 return stopListening(element, eventName, fn);
6125 * Fires when the document is ready (before onload and before images are loaded). Can be
6126 * accessed shorthanded Roo.onReady().
6127 * @param {Function} fn The method the event invokes
6128 * @param {Object} scope An object that becomes the scope of the handler
6129 * @param {boolean} options
6131 onDocumentReady : function(fn, scope, options){
6132 if(docReadyState){ // if it already fired
6133 docReadyEvent.addListener(fn, scope, options);
6134 docReadyEvent.fire();
6135 docReadyEvent.clearListeners();
6141 docReadyEvent.addListener(fn, scope, options);
6145 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6146 * @param {Function} fn The method the event invokes
6147 * @param {Object} scope An object that becomes the scope of the handler
6148 * @param {boolean} options
6150 onWindowResize : function(fn, scope, options){
6152 resizeEvent = new Roo.util.Event();
6153 resizeTask = new Roo.util.DelayedTask(function(){
6154 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6156 E.on(window, "resize", function(){
6158 resizeTask.delay(50);
6160 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6164 resizeEvent.addListener(fn, scope, options);
6168 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6169 * @param {Function} fn The method the event invokes
6170 * @param {Object} scope An object that becomes the scope of the handler
6171 * @param {boolean} options
6173 onTextResize : function(fn, scope, options){
6175 textEvent = new Roo.util.Event();
6176 var textEl = new Roo.Element(document.createElement('div'));
6177 textEl.dom.className = 'x-text-resize';
6178 textEl.dom.innerHTML = 'X';
6179 textEl.appendTo(document.body);
6180 textSize = textEl.dom.offsetHeight;
6181 setInterval(function(){
6182 if(textEl.dom.offsetHeight != textSize){
6183 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6185 }, this.textResizeInterval);
6187 textEvent.addListener(fn, scope, options);
6191 * Removes the passed window resize listener.
6192 * @param {Function} fn The method the event invokes
6193 * @param {Object} scope The scope of handler
6195 removeResizeListener : function(fn, scope){
6197 resizeEvent.removeListener(fn, scope);
6202 fireResize : function(){
6204 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6208 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6212 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6214 textResizeInterval : 50
6219 * @scopeAlias pub=Roo.EventManager
6223 * Appends an event handler to an element (shorthand for addListener)
6224 * @param {String/HTMLElement} element The html element or id to assign the
6225 * @param {String} eventName The type of event to listen for
6226 * @param {Function} handler The method the event invokes
6227 * @param {Object} scope (optional) The scope in which to execute the handler
6228 * function. The handler function's "this" context.
6229 * @param {Object} options (optional) An object containing handler configuration
6230 * properties. This may contain any of the following properties:<ul>
6231 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6232 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6233 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6234 * <li>preventDefault {Boolean} True to prevent the default action</li>
6235 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6236 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6237 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6238 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6239 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6240 * by the specified number of milliseconds. If the event fires again within that time, the original
6241 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6244 * <b>Combining Options</b><br>
6245 * Using the options argument, it is possible to combine different types of listeners:<br>
6247 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6249 el.on('click', this.onClick, this, {
6256 * <b>Attaching multiple handlers in 1 call</b><br>
6257 * The method also allows for a single argument to be passed which is a config object containing properties
6258 * which specify multiple handlers.
6268 fn: this.onMouseOver
6277 * Or a shorthand syntax:<br>
6280 'click' : this.onClick,
6281 'mouseover' : this.onMouseOver,
6282 'mouseout' : this.onMouseOut
6286 pub.on = pub.addListener;
6287 pub.un = pub.removeListener;
6289 pub.stoppedMouseDownEvent = new Roo.util.Event();
6293 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6294 * @param {Function} fn The method the event invokes
6295 * @param {Object} scope An object that becomes the scope of the handler
6296 * @param {boolean} override If true, the obj passed in becomes
6297 * the execution scope of the listener
6301 Roo.onReady = Roo.EventManager.onDocumentReady;
6303 Roo.onReady(function(){
6304 var bd = Roo.get(document.body);
6309 : Roo.isGecko ? "roo-gecko"
6310 : Roo.isOpera ? "roo-opera"
6311 : Roo.isSafari ? "roo-safari" : ""];
6314 cls.push("roo-mac");
6317 cls.push("roo-linux");
6319 if(Roo.isBorderBox){
6320 cls.push('roo-border-box');
6322 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6323 var p = bd.dom.parentNode;
6325 p.className += ' roo-strict';
6328 bd.addClass(cls.join(' '));
6332 * @class Roo.EventObject
6333 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6334 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6337 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6339 var target = e.getTarget();
6342 var myDiv = Roo.get("myDiv");
6343 myDiv.on("click", handleClick);
6345 Roo.EventManager.on("myDiv", 'click', handleClick);
6346 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6350 Roo.EventObject = function(){
6352 var E = Roo.lib.Event;
6354 // safari keypress events for special keys return bad keycodes
6357 63235 : 39, // right
6360 63276 : 33, // page up
6361 63277 : 34, // page down
6362 63272 : 46, // delete
6367 // normalize button clicks
6368 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6369 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6371 Roo.EventObjectImpl = function(e){
6373 this.setEvent(e.browserEvent || e);
6376 Roo.EventObjectImpl.prototype = {
6378 * Used to fix doc tools.
6379 * @scope Roo.EventObject.prototype
6385 /** The normal browser event */
6386 browserEvent : null,
6387 /** The button pressed in a mouse event */
6389 /** True if the shift key was down during the event */
6391 /** True if the control key was down during the event */
6393 /** True if the alt key was down during the event */
6452 setEvent : function(e){
6453 if(e == this || (e && e.browserEvent)){ // already wrapped
6456 this.browserEvent = e;
6458 // normalize buttons
6459 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6460 if(e.type == 'click' && this.button == -1){
6464 this.shiftKey = e.shiftKey;
6465 // mac metaKey behaves like ctrlKey
6466 this.ctrlKey = e.ctrlKey || e.metaKey;
6467 this.altKey = e.altKey;
6468 // in getKey these will be normalized for the mac
6469 this.keyCode = e.keyCode;
6470 // keyup warnings on firefox.
6471 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6472 // cache the target for the delayed and or buffered events
6473 this.target = E.getTarget(e);
6475 this.xy = E.getXY(e);
6478 this.shiftKey = false;
6479 this.ctrlKey = false;
6480 this.altKey = false;
6490 * Stop the event (preventDefault and stopPropagation)
6492 stopEvent : function(){
6493 if(this.browserEvent){
6494 if(this.browserEvent.type == 'mousedown'){
6495 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6497 E.stopEvent(this.browserEvent);
6502 * Prevents the browsers default handling of the event.
6504 preventDefault : function(){
6505 if(this.browserEvent){
6506 E.preventDefault(this.browserEvent);
6511 isNavKeyPress : function(){
6512 var k = this.keyCode;
6513 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6514 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6517 isSpecialKey : function(){
6518 var k = this.keyCode;
6519 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6520 (k == 16) || (k == 17) ||
6521 (k >= 18 && k <= 20) ||
6522 (k >= 33 && k <= 35) ||
6523 (k >= 36 && k <= 39) ||
6524 (k >= 44 && k <= 45);
6527 * Cancels bubbling of the event.
6529 stopPropagation : function(){
6530 if(this.browserEvent){
6531 if(this.type == 'mousedown'){
6532 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6534 E.stopPropagation(this.browserEvent);
6539 * Gets the key code for the event.
6542 getCharCode : function(){
6543 return this.charCode || this.keyCode;
6547 * Returns a normalized keyCode for the event.
6548 * @return {Number} The key code
6550 getKey : function(){
6551 var k = this.keyCode || this.charCode;
6552 return Roo.isSafari ? (safariKeys[k] || k) : k;
6556 * Gets the x coordinate of the event.
6559 getPageX : function(){
6564 * Gets the y coordinate of the event.
6567 getPageY : function(){
6572 * Gets the time of the event.
6575 getTime : function(){
6576 if(this.browserEvent){
6577 return E.getTime(this.browserEvent);
6583 * Gets the page coordinates of the event.
6584 * @return {Array} The xy values like [x, y]
6591 * Gets the target for the event.
6592 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6593 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6594 search as a number or element (defaults to 10 || document.body)
6595 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6596 * @return {HTMLelement}
6598 getTarget : function(selector, maxDepth, returnEl){
6599 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6602 * Gets the related target.
6603 * @return {HTMLElement}
6605 getRelatedTarget : function(){
6606 if(this.browserEvent){
6607 return E.getRelatedTarget(this.browserEvent);
6613 * Normalizes mouse wheel delta across browsers
6614 * @return {Number} The delta
6616 getWheelDelta : function(){
6617 var e = this.browserEvent;
6619 if(e.wheelDelta){ /* IE/Opera. */
6620 delta = e.wheelDelta/120;
6621 }else if(e.detail){ /* Mozilla case. */
6622 delta = -e.detail/3;
6628 * Returns true if the control, meta, shift or alt key was pressed during this event.
6631 hasModifier : function(){
6632 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6636 * Returns true if the target of this event equals el or is a child of el
6637 * @param {String/HTMLElement/Element} el
6638 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6641 within : function(el, related){
6642 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6643 return t && Roo.fly(el).contains(t);
6646 getPoint : function(){
6647 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6651 return new Roo.EventObjectImpl();
6656 * Ext JS Library 1.1.1
6657 * Copyright(c) 2006-2007, Ext JS, LLC.
6659 * Originally Released Under LGPL - original licence link has changed is not relivant.
6662 * <script type="text/javascript">
6666 // was in Composite Element!??!?!
6669 var D = Roo.lib.Dom;
6670 var E = Roo.lib.Event;
6671 var A = Roo.lib.Anim;
6673 // local style camelizing for speed
6675 var camelRe = /(-[a-z])/gi;
6676 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6677 var view = document.defaultView;
6680 * @class Roo.Element
6681 * Represents an Element in the DOM.<br><br>
6684 var el = Roo.get("my-div");
6687 var el = getEl("my-div");
6689 // or with a DOM element
6690 var el = Roo.get(myDivElement);
6692 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6693 * each call instead of constructing a new one.<br><br>
6694 * <b>Animations</b><br />
6695 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6696 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6698 Option Default Description
6699 --------- -------- ---------------------------------------------
6700 duration .35 The duration of the animation in seconds
6701 easing easeOut The YUI easing method
6702 callback none A function to execute when the anim completes
6703 scope this The scope (this) of the callback function
6705 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6706 * manipulate the animation. Here's an example:
6708 var el = Roo.get("my-div");
6713 // default animation
6714 el.setWidth(100, true);
6716 // animation with some options set
6723 // using the "anim" property to get the Anim object
6729 el.setWidth(100, opt);
6731 if(opt.anim.isAnimated()){
6735 * <b> Composite (Collections of) Elements</b><br />
6736 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6737 * @constructor Create a new Element directly.
6738 * @param {String/HTMLElement} element
6739 * @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).
6741 Roo.Element = function(element, forceNew){
6742 var dom = typeof element == "string" ?
6743 document.getElementById(element) : element;
6744 if(!dom){ // invalid id/element
6748 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6749 return Roo.Element.cache[id];
6759 * The DOM element ID
6762 this.id = id || Roo.id(dom);
6765 var El = Roo.Element;
6769 * The element's default display mode (defaults to "")
6772 originalDisplay : "",
6776 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6781 * Sets the element's visibility mode. When setVisible() is called it
6782 * will use this to determine whether to set the visibility or the display property.
6783 * @param visMode Element.VISIBILITY or Element.DISPLAY
6784 * @return {Roo.Element} this
6786 setVisibilityMode : function(visMode){
6787 this.visibilityMode = visMode;
6791 * Convenience method for setVisibilityMode(Element.DISPLAY)
6792 * @param {String} display (optional) What to set display to when visible
6793 * @return {Roo.Element} this
6795 enableDisplayMode : function(display){
6796 this.setVisibilityMode(El.DISPLAY);
6797 if(typeof display != "undefined") this.originalDisplay = display;
6802 * 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)
6803 * @param {String} selector The simple selector to test
6804 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6805 search as a number or element (defaults to 10 || document.body)
6806 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6807 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6809 findParent : function(simpleSelector, maxDepth, returnEl){
6810 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6811 maxDepth = maxDepth || 50;
6812 if(typeof maxDepth != "number"){
6813 stopEl = Roo.getDom(maxDepth);
6816 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6817 if(dq.is(p, simpleSelector)){
6818 return returnEl ? Roo.get(p) : p;
6828 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6829 * @param {String} selector The simple selector to test
6830 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6831 search as a number or element (defaults to 10 || document.body)
6832 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6833 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6835 findParentNode : function(simpleSelector, maxDepth, returnEl){
6836 var p = Roo.fly(this.dom.parentNode, '_internal');
6837 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6841 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6842 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6843 * @param {String} selector The simple selector to test
6844 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6845 search as a number or element (defaults to 10 || document.body)
6846 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6848 up : function(simpleSelector, maxDepth){
6849 return this.findParentNode(simpleSelector, maxDepth, true);
6855 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6856 * @param {String} selector The simple selector to test
6857 * @return {Boolean} True if this element matches the selector, else false
6859 is : function(simpleSelector){
6860 return Roo.DomQuery.is(this.dom, simpleSelector);
6864 * Perform animation on this element.
6865 * @param {Object} args The YUI animation control args
6866 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6867 * @param {Function} onComplete (optional) Function to call when animation completes
6868 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6869 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6870 * @return {Roo.Element} this
6872 animate : function(args, duration, onComplete, easing, animType){
6873 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6878 * @private Internal animation call
6880 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6881 animType = animType || 'run';
6883 var anim = Roo.lib.Anim[animType](
6885 (opt.duration || defaultDur) || .35,
6886 (opt.easing || defaultEase) || 'easeOut',
6888 Roo.callback(cb, this);
6889 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6897 // private legacy anim prep
6898 preanim : function(a, i){
6899 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6903 * Removes worthless text nodes
6904 * @param {Boolean} forceReclean (optional) By default the element
6905 * keeps track if it has been cleaned already so
6906 * you can call this over and over. However, if you update the element and
6907 * need to force a reclean, you can pass true.
6909 clean : function(forceReclean){
6910 if(this.isCleaned && forceReclean !== true){
6914 var d = this.dom, n = d.firstChild, ni = -1;
6916 var nx = n.nextSibling;
6917 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6924 this.isCleaned = true;
6929 calcOffsetsTo : function(el){
6932 var restorePos = false;
6933 if(el.getStyle('position') == 'static'){
6934 el.position('relative');
6939 while(op && op != d && op.tagName != 'HTML'){
6942 op = op.offsetParent;
6945 el.position('static');
6951 * Scrolls this element into view within the passed container.
6952 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6953 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6954 * @return {Roo.Element} this
6956 scrollIntoView : function(container, hscroll){
6957 var c = Roo.getDom(container) || document.body;
6960 var o = this.calcOffsetsTo(c),
6963 b = t+el.offsetHeight,
6964 r = l+el.offsetWidth;
6966 var ch = c.clientHeight;
6967 var ct = parseInt(c.scrollTop, 10);
6968 var cl = parseInt(c.scrollLeft, 10);
6970 var cr = cl + c.clientWidth;
6978 if(hscroll !== false){
6982 c.scrollLeft = r-c.clientWidth;
6989 scrollChildIntoView : function(child, hscroll){
6990 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6994 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6995 * the new height may not be available immediately.
6996 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6997 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6998 * @param {Function} onComplete (optional) Function to call when animation completes
6999 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7000 * @return {Roo.Element} this
7002 autoHeight : function(animate, duration, onComplete, easing){
7003 var oldHeight = this.getHeight();
7005 this.setHeight(1); // force clipping
7006 setTimeout(function(){
7007 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7009 this.setHeight(height);
7011 if(typeof onComplete == "function"){
7015 this.setHeight(oldHeight); // restore original height
7016 this.setHeight(height, animate, duration, function(){
7018 if(typeof onComplete == "function") onComplete();
7019 }.createDelegate(this), easing);
7021 }.createDelegate(this), 0);
7026 * Returns true if this element is an ancestor of the passed element
7027 * @param {HTMLElement/String} el The element to check
7028 * @return {Boolean} True if this element is an ancestor of el, else false
7030 contains : function(el){
7031 if(!el){return false;}
7032 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7036 * Checks whether the element is currently visible using both visibility and display properties.
7037 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7038 * @return {Boolean} True if the element is currently visible, else false
7040 isVisible : function(deep) {
7041 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7042 if(deep !== true || !vis){
7045 var p = this.dom.parentNode;
7046 while(p && p.tagName.toLowerCase() != "body"){
7047 if(!Roo.fly(p, '_isVisible').isVisible()){
7056 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7057 * @param {String} selector The CSS selector
7058 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7059 * @return {CompositeElement/CompositeElementLite} The composite element
7061 select : function(selector, unique){
7062 return El.select(selector, unique, this.dom);
7066 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7067 * @param {String} selector The CSS selector
7068 * @return {Array} An array of the matched nodes
7070 query : function(selector, unique){
7071 return Roo.DomQuery.select(selector, this.dom);
7075 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7076 * @param {String} selector The CSS selector
7077 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7078 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7080 child : function(selector, returnDom){
7081 var n = Roo.DomQuery.selectNode(selector, this.dom);
7082 return returnDom ? n : Roo.get(n);
7086 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7087 * @param {String} selector The CSS selector
7088 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7089 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7091 down : function(selector, returnDom){
7092 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7093 return returnDom ? n : Roo.get(n);
7097 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7098 * @param {String} group The group the DD object is member of
7099 * @param {Object} config The DD config object
7100 * @param {Object} overrides An object containing methods to override/implement on the DD object
7101 * @return {Roo.dd.DD} The DD object
7103 initDD : function(group, config, overrides){
7104 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7105 return Roo.apply(dd, overrides);
7109 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7110 * @param {String} group The group the DDProxy object is member of
7111 * @param {Object} config The DDProxy config object
7112 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7113 * @return {Roo.dd.DDProxy} The DDProxy object
7115 initDDProxy : function(group, config, overrides){
7116 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7117 return Roo.apply(dd, overrides);
7121 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7122 * @param {String} group The group the DDTarget object is member of
7123 * @param {Object} config The DDTarget config object
7124 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7125 * @return {Roo.dd.DDTarget} The DDTarget object
7127 initDDTarget : function(group, config, overrides){
7128 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7129 return Roo.apply(dd, overrides);
7133 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7134 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7135 * @param {Boolean} visible Whether the element is visible
7136 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7137 * @return {Roo.Element} this
7139 setVisible : function(visible, animate){
7141 if(this.visibilityMode == El.DISPLAY){
7142 this.setDisplayed(visible);
7145 this.dom.style.visibility = visible ? "visible" : "hidden";
7148 // closure for composites
7150 var visMode = this.visibilityMode;
7152 this.setOpacity(.01);
7153 this.setVisible(true);
7155 this.anim({opacity: { to: (visible?1:0) }},
7156 this.preanim(arguments, 1),
7157 null, .35, 'easeIn', function(){
7159 if(visMode == El.DISPLAY){
7160 dom.style.display = "none";
7162 dom.style.visibility = "hidden";
7164 Roo.get(dom).setOpacity(1);
7172 * Returns true if display is not "none"
7175 isDisplayed : function() {
7176 return this.getStyle("display") != "none";
7180 * Toggles the element's visibility or display, depending on visibility mode.
7181 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7182 * @return {Roo.Element} this
7184 toggle : function(animate){
7185 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7190 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7191 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7192 * @return {Roo.Element} this
7194 setDisplayed : function(value) {
7195 if(typeof value == "boolean"){
7196 value = value ? this.originalDisplay : "none";
7198 this.setStyle("display", value);
7203 * Tries to focus the element. Any exceptions are caught and ignored.
7204 * @return {Roo.Element} this
7206 focus : function() {
7214 * Tries to blur the element. Any exceptions are caught and ignored.
7215 * @return {Roo.Element} this
7225 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7226 * @param {String/Array} className The CSS class to add, or an array of classes
7227 * @return {Roo.Element} this
7229 addClass : function(className){
7230 if(className instanceof Array){
7231 for(var i = 0, len = className.length; i < len; i++) {
7232 this.addClass(className[i]);
7235 if(className && !this.hasClass(className)){
7236 this.dom.className = this.dom.className + " " + className;
7243 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7244 * @param {String/Array} className The CSS class to add, or an array of classes
7245 * @return {Roo.Element} this
7247 radioClass : function(className){
7248 var siblings = this.dom.parentNode.childNodes;
7249 for(var i = 0; i < siblings.length; i++) {
7250 var s = siblings[i];
7251 if(s.nodeType == 1){
7252 Roo.get(s).removeClass(className);
7255 this.addClass(className);
7260 * Removes one or more CSS classes from the element.
7261 * @param {String/Array} className The CSS class to remove, or an array of classes
7262 * @return {Roo.Element} this
7264 removeClass : function(className){
7265 if(!className || !this.dom.className){
7268 if(className instanceof Array){
7269 for(var i = 0, len = className.length; i < len; i++) {
7270 this.removeClass(className[i]);
7273 if(this.hasClass(className)){
7274 var re = this.classReCache[className];
7276 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7277 this.classReCache[className] = re;
7279 this.dom.className =
7280 this.dom.className.replace(re, " ");
7290 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7291 * @param {String} className The CSS class to toggle
7292 * @return {Roo.Element} this
7294 toggleClass : function(className){
7295 if(this.hasClass(className)){
7296 this.removeClass(className);
7298 this.addClass(className);
7304 * Checks if the specified CSS class exists on this element's DOM node.
7305 * @param {String} className The CSS class to check for
7306 * @return {Boolean} True if the class exists, else false
7308 hasClass : function(className){
7309 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7313 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7314 * @param {String} oldClassName The CSS class to replace
7315 * @param {String} newClassName The replacement CSS class
7316 * @return {Roo.Element} this
7318 replaceClass : function(oldClassName, newClassName){
7319 this.removeClass(oldClassName);
7320 this.addClass(newClassName);
7325 * Returns an object with properties matching the styles requested.
7326 * For example, el.getStyles('color', 'font-size', 'width') might return
7327 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7328 * @param {String} style1 A style name
7329 * @param {String} style2 A style name
7330 * @param {String} etc.
7331 * @return {Object} The style object
7333 getStyles : function(){
7334 var a = arguments, len = a.length, r = {};
7335 for(var i = 0; i < len; i++){
7336 r[a[i]] = this.getStyle(a[i]);
7342 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7343 * @param {String} property The style property whose value is returned.
7344 * @return {String} The current value of the style property for this element.
7346 getStyle : function(){
7347 return view && view.getComputedStyle ?
7349 var el = this.dom, v, cs, camel;
7350 if(prop == 'float'){
7353 if(el.style && (v = el.style[prop])){
7356 if(cs = view.getComputedStyle(el, "")){
7357 if(!(camel = propCache[prop])){
7358 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7365 var el = this.dom, v, cs, camel;
7366 if(prop == 'opacity'){
7367 if(typeof el.style.filter == 'string'){
7368 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7370 var fv = parseFloat(m[1]);
7372 return fv ? fv / 100 : 0;
7377 }else if(prop == 'float'){
7378 prop = "styleFloat";
7380 if(!(camel = propCache[prop])){
7381 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7383 if(v = el.style[camel]){
7386 if(cs = el.currentStyle){
7394 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7395 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7396 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7397 * @return {Roo.Element} this
7399 setStyle : function(prop, value){
7400 if(typeof prop == "string"){
7402 if (prop == 'float') {
7403 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7408 if(!(camel = propCache[prop])){
7409 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7412 if(camel == 'opacity') {
7413 this.setOpacity(value);
7415 this.dom.style[camel] = value;
7418 for(var style in prop){
7419 if(typeof prop[style] != "function"){
7420 this.setStyle(style, prop[style]);
7428 * More flexible version of {@link #setStyle} for setting style properties.
7429 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7430 * a function which returns such a specification.
7431 * @return {Roo.Element} this
7433 applyStyles : function(style){
7434 Roo.DomHelper.applyStyles(this.dom, style);
7439 * 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).
7440 * @return {Number} The X position of the element
7443 return D.getX(this.dom);
7447 * 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).
7448 * @return {Number} The Y position of the element
7451 return D.getY(this.dom);
7455 * 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).
7456 * @return {Array} The XY position of the element
7459 return D.getXY(this.dom);
7463 * 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).
7464 * @param {Number} The X position of the element
7465 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7466 * @return {Roo.Element} this
7468 setX : function(x, animate){
7470 D.setX(this.dom, x);
7472 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7478 * 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).
7479 * @param {Number} The Y position of the element
7480 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7481 * @return {Roo.Element} this
7483 setY : function(y, animate){
7485 D.setY(this.dom, y);
7487 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7493 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7494 * @param {String} left The left CSS property value
7495 * @return {Roo.Element} this
7497 setLeft : function(left){
7498 this.setStyle("left", this.addUnits(left));
7503 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7504 * @param {String} top The top CSS property value
7505 * @return {Roo.Element} this
7507 setTop : function(top){
7508 this.setStyle("top", this.addUnits(top));
7513 * Sets the element's CSS right style.
7514 * @param {String} right The right CSS property value
7515 * @return {Roo.Element} this
7517 setRight : function(right){
7518 this.setStyle("right", this.addUnits(right));
7523 * Sets the element's CSS bottom style.
7524 * @param {String} bottom The bottom CSS property value
7525 * @return {Roo.Element} this
7527 setBottom : function(bottom){
7528 this.setStyle("bottom", this.addUnits(bottom));
7533 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7534 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7535 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7536 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7537 * @return {Roo.Element} this
7539 setXY : function(pos, animate){
7541 D.setXY(this.dom, pos);
7543 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7549 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7550 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7551 * @param {Number} x X value for new position (coordinates are page-based)
7552 * @param {Number} y Y value for new position (coordinates are page-based)
7553 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7554 * @return {Roo.Element} this
7556 setLocation : function(x, y, animate){
7557 this.setXY([x, y], this.preanim(arguments, 2));
7562 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7563 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7564 * @param {Number} x X value for new position (coordinates are page-based)
7565 * @param {Number} y Y value for new position (coordinates are page-based)
7566 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7567 * @return {Roo.Element} this
7569 moveTo : function(x, y, animate){
7570 this.setXY([x, y], this.preanim(arguments, 2));
7575 * Returns the region of the given element.
7576 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7577 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7579 getRegion : function(){
7580 return D.getRegion(this.dom);
7584 * Returns the offset height of the element
7585 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7586 * @return {Number} The element's height
7588 getHeight : function(contentHeight){
7589 var h = this.dom.offsetHeight || 0;
7590 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7594 * Returns the offset width of the element
7595 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7596 * @return {Number} The element's width
7598 getWidth : function(contentWidth){
7599 var w = this.dom.offsetWidth || 0;
7600 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7604 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7605 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7606 * if a height has not been set using CSS.
7609 getComputedHeight : function(){
7610 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7612 h = parseInt(this.getStyle('height'), 10) || 0;
7613 if(!this.isBorderBox()){
7614 h += this.getFrameWidth('tb');
7621 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7622 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7623 * if a width has not been set using CSS.
7626 getComputedWidth : function(){
7627 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7629 w = parseInt(this.getStyle('width'), 10) || 0;
7630 if(!this.isBorderBox()){
7631 w += this.getFrameWidth('lr');
7638 * Returns the size of the element.
7639 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7640 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7642 getSize : function(contentSize){
7643 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7647 * Returns the width and height of the viewport.
7648 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7650 getViewSize : function(){
7651 var d = this.dom, doc = document, aw = 0, ah = 0;
7652 if(d == doc || d == doc.body){
7653 return {width : D.getViewWidth(), height: D.getViewHeight()};
7656 width : d.clientWidth,
7657 height: d.clientHeight
7663 * Returns the value of the "value" attribute
7664 * @param {Boolean} asNumber true to parse the value as a number
7665 * @return {String/Number}
7667 getValue : function(asNumber){
7668 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7672 adjustWidth : function(width){
7673 if(typeof width == "number"){
7674 if(this.autoBoxAdjust && !this.isBorderBox()){
7675 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7685 adjustHeight : function(height){
7686 if(typeof height == "number"){
7687 if(this.autoBoxAdjust && !this.isBorderBox()){
7688 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7698 * Set the width of the element
7699 * @param {Number} width The new width
7700 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7701 * @return {Roo.Element} this
7703 setWidth : function(width, animate){
7704 width = this.adjustWidth(width);
7706 this.dom.style.width = this.addUnits(width);
7708 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7714 * Set the height of the element
7715 * @param {Number} height The new height
7716 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7717 * @return {Roo.Element} this
7719 setHeight : function(height, animate){
7720 height = this.adjustHeight(height);
7722 this.dom.style.height = this.addUnits(height);
7724 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7730 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7731 * @param {Number} width The new width
7732 * @param {Number} height The new height
7733 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7734 * @return {Roo.Element} this
7736 setSize : function(width, height, animate){
7737 if(typeof width == "object"){ // in case of object from getSize()
7738 height = width.height; width = width.width;
7740 width = this.adjustWidth(width); height = this.adjustHeight(height);
7742 this.dom.style.width = this.addUnits(width);
7743 this.dom.style.height = this.addUnits(height);
7745 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7751 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7752 * @param {Number} x X value for new position (coordinates are page-based)
7753 * @param {Number} y Y value for new position (coordinates are page-based)
7754 * @param {Number} width The new width
7755 * @param {Number} height The new height
7756 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7757 * @return {Roo.Element} this
7759 setBounds : function(x, y, width, height, animate){
7761 this.setSize(width, height);
7762 this.setLocation(x, y);
7764 width = this.adjustWidth(width); height = this.adjustHeight(height);
7765 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7766 this.preanim(arguments, 4), 'motion');
7772 * 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.
7773 * @param {Roo.lib.Region} region The region to fill
7774 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7775 * @return {Roo.Element} this
7777 setRegion : function(region, animate){
7778 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7783 * Appends an event handler
7785 * @param {String} eventName The type of event to append
7786 * @param {Function} fn The method the event invokes
7787 * @param {Object} scope (optional) The scope (this object) of the fn
7788 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7790 addListener : function(eventName, fn, scope, options){
7791 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7795 * Removes an event handler from this element
7796 * @param {String} eventName the type of event to remove
7797 * @param {Function} fn the method the event invokes
7798 * @return {Roo.Element} this
7800 removeListener : function(eventName, fn){
7801 Roo.EventManager.removeListener(this.dom, eventName, fn);
7806 * Removes all previous added listeners from this element
7807 * @return {Roo.Element} this
7809 removeAllListeners : function(){
7810 E.purgeElement(this.dom);
7814 relayEvent : function(eventName, observable){
7815 this.on(eventName, function(e){
7816 observable.fireEvent(eventName, e);
7821 * Set the opacity of the element
7822 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7823 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7824 * @return {Roo.Element} this
7826 setOpacity : function(opacity, animate){
7828 var s = this.dom.style;
7831 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7832 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7834 s.opacity = opacity;
7837 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7843 * Gets the left X coordinate
7844 * @param {Boolean} local True to get the local css position instead of page coordinate
7847 getLeft : function(local){
7851 return parseInt(this.getStyle("left"), 10) || 0;
7856 * Gets the right X coordinate of the element (element X position + element width)
7857 * @param {Boolean} local True to get the local css position instead of page coordinate
7860 getRight : function(local){
7862 return this.getX() + this.getWidth();
7864 return (this.getLeft(true) + this.getWidth()) || 0;
7869 * Gets the top Y coordinate
7870 * @param {Boolean} local True to get the local css position instead of page coordinate
7873 getTop : function(local) {
7877 return parseInt(this.getStyle("top"), 10) || 0;
7882 * Gets the bottom Y coordinate of the element (element Y position + element height)
7883 * @param {Boolean} local True to get the local css position instead of page coordinate
7886 getBottom : function(local){
7888 return this.getY() + this.getHeight();
7890 return (this.getTop(true) + this.getHeight()) || 0;
7895 * Initializes positioning on this element. If a desired position is not passed, it will make the
7896 * the element positioned relative IF it is not already positioned.
7897 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7898 * @param {Number} zIndex (optional) The zIndex to apply
7899 * @param {Number} x (optional) Set the page X position
7900 * @param {Number} y (optional) Set the page Y position
7902 position : function(pos, zIndex, x, y){
7904 if(this.getStyle('position') == 'static'){
7905 this.setStyle('position', 'relative');
7908 this.setStyle("position", pos);
7911 this.setStyle("z-index", zIndex);
7913 if(x !== undefined && y !== undefined){
7915 }else if(x !== undefined){
7917 }else if(y !== undefined){
7923 * Clear positioning back to the default when the document was loaded
7924 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7925 * @return {Roo.Element} this
7927 clearPositioning : function(value){
7935 "position" : "static"
7941 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7942 * snapshot before performing an update and then restoring the element.
7945 getPositioning : function(){
7946 var l = this.getStyle("left");
7947 var t = this.getStyle("top");
7949 "position" : this.getStyle("position"),
7951 "right" : l ? "" : this.getStyle("right"),
7953 "bottom" : t ? "" : this.getStyle("bottom"),
7954 "z-index" : this.getStyle("z-index")
7959 * Gets the width of the border(s) for the specified side(s)
7960 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7961 * passing lr would get the border (l)eft width + the border (r)ight width.
7962 * @return {Number} The width of the sides passed added together
7964 getBorderWidth : function(side){
7965 return this.addStyles(side, El.borders);
7969 * Gets the width of the padding(s) for the specified side(s)
7970 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7971 * passing lr would get the padding (l)eft + the padding (r)ight.
7972 * @return {Number} The padding of the sides passed added together
7974 getPadding : function(side){
7975 return this.addStyles(side, El.paddings);
7979 * Set positioning with an object returned by getPositioning().
7980 * @param {Object} posCfg
7981 * @return {Roo.Element} this
7983 setPositioning : function(pc){
7984 this.applyStyles(pc);
7985 if(pc.right == "auto"){
7986 this.dom.style.right = "";
7988 if(pc.bottom == "auto"){
7989 this.dom.style.bottom = "";
7995 fixDisplay : function(){
7996 if(this.getStyle("display") == "none"){
7997 this.setStyle("visibility", "hidden");
7998 this.setStyle("display", this.originalDisplay); // first try reverting to default
7999 if(this.getStyle("display") == "none"){ // if that fails, default to block
8000 this.setStyle("display", "block");
8006 * Quick set left and top adding default units
8007 * @param {String} left The left CSS property value
8008 * @param {String} top The top CSS property value
8009 * @return {Roo.Element} this
8011 setLeftTop : function(left, top){
8012 this.dom.style.left = this.addUnits(left);
8013 this.dom.style.top = this.addUnits(top);
8018 * Move this element relative to its current position.
8019 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8020 * @param {Number} distance How far to move the element in pixels
8021 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8022 * @return {Roo.Element} this
8024 move : function(direction, distance, animate){
8025 var xy = this.getXY();
8026 direction = direction.toLowerCase();
8030 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8034 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8039 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8044 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8051 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8052 * @return {Roo.Element} this
8055 if(!this.isClipped){
8056 this.isClipped = true;
8057 this.originalClip = {
8058 "o": this.getStyle("overflow"),
8059 "x": this.getStyle("overflow-x"),
8060 "y": this.getStyle("overflow-y")
8062 this.setStyle("overflow", "hidden");
8063 this.setStyle("overflow-x", "hidden");
8064 this.setStyle("overflow-y", "hidden");
8070 * Return clipping (overflow) to original clipping before clip() was called
8071 * @return {Roo.Element} this
8073 unclip : function(){
8075 this.isClipped = false;
8076 var o = this.originalClip;
8077 if(o.o){this.setStyle("overflow", o.o);}
8078 if(o.x){this.setStyle("overflow-x", o.x);}
8079 if(o.y){this.setStyle("overflow-y", o.y);}
8086 * Gets the x,y coordinates specified by the anchor position on the element.
8087 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8088 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8089 * {width: (target width), height: (target height)} (defaults to the element's current size)
8090 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8091 * @return {Array} [x, y] An array containing the element's x and y coordinates
8093 getAnchorXY : function(anchor, local, s){
8094 //Passing a different size is useful for pre-calculating anchors,
8095 //especially for anchored animations that change the el size.
8097 var w, h, vp = false;
8100 if(d == document.body || d == document){
8102 w = D.getViewWidth(); h = D.getViewHeight();
8104 w = this.getWidth(); h = this.getHeight();
8107 w = s.width; h = s.height;
8109 var x = 0, y = 0, r = Math.round;
8110 switch((anchor || "tl").toLowerCase()){
8152 var sc = this.getScroll();
8153 return [x + sc.left, y + sc.top];
8155 //Add the element's offset xy
8156 var o = this.getXY();
8157 return [x+o[0], y+o[1]];
8161 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8162 * supported position values.
8163 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8164 * @param {String} position The position to align to.
8165 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8166 * @return {Array} [x, y]
8168 getAlignToXY : function(el, p, o){
8172 throw "Element.alignTo with an element that doesn't exist";
8174 var c = false; //constrain to viewport
8175 var p1 = "", p2 = "";
8182 }else if(p.indexOf("-") == -1){
8185 p = p.toLowerCase();
8186 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8188 throw "Element.alignTo with an invalid alignment " + p;
8190 p1 = m[1]; p2 = m[2]; c = !!m[3];
8192 //Subtract the aligned el's internal xy from the target's offset xy
8193 //plus custom offset to get the aligned el's new offset xy
8194 var a1 = this.getAnchorXY(p1, true);
8195 var a2 = el.getAnchorXY(p2, false);
8196 var x = a2[0] - a1[0] + o[0];
8197 var y = a2[1] - a1[1] + o[1];
8199 //constrain the aligned el to viewport if necessary
8200 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8201 // 5px of margin for ie
8202 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8204 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8205 //perpendicular to the vp border, allow the aligned el to slide on that border,
8206 //otherwise swap the aligned el to the opposite border of the target.
8207 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8208 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8209 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8210 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8213 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8214 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8216 if((x+w) > dw + scrollX){
8217 x = swapX ? r.left-w : dw+scrollX-w;
8220 x = swapX ? r.right : scrollX;
8222 if((y+h) > dh + scrollY){
8223 y = swapY ? r.top-h : dh+scrollY-h;
8226 y = swapY ? r.bottom : scrollY;
8233 getConstrainToXY : function(){
8234 var os = {top:0, left:0, bottom:0, right: 0};
8236 return function(el, local, offsets, proposedXY){
8238 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8240 var vw, vh, vx = 0, vy = 0;
8241 if(el.dom == document.body || el.dom == document){
8242 vw = Roo.lib.Dom.getViewWidth();
8243 vh = Roo.lib.Dom.getViewHeight();
8245 vw = el.dom.clientWidth;
8246 vh = el.dom.clientHeight;
8248 var vxy = el.getXY();
8254 var s = el.getScroll();
8256 vx += offsets.left + s.left;
8257 vy += offsets.top + s.top;
8259 vw -= offsets.right;
8260 vh -= offsets.bottom;
8265 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8266 var x = xy[0], y = xy[1];
8267 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8269 // only move it if it needs it
8272 // first validate right/bottom
8281 // then make sure top/left isn't negative
8290 return moved ? [x, y] : false;
8295 adjustForConstraints : function(xy, parent, offsets){
8296 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8300 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8301 * document it aligns it to the viewport.
8302 * The position parameter is optional, and can be specified in any one of the following formats:
8304 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8305 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8306 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8307 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8308 * <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
8309 * element's anchor point, and the second value is used as the target's anchor point.</li>
8311 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8312 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8313 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8314 * that specified in order to enforce the viewport constraints.
8315 * Following are all of the supported anchor positions:
8318 ----- -----------------------------
8319 tl The top left corner (default)
8320 t The center of the top edge
8321 tr The top right corner
8322 l The center of the left edge
8323 c In the center of the element
8324 r The center of the right edge
8325 bl The bottom left corner
8326 b The center of the bottom edge
8327 br The bottom right corner
8331 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8332 el.alignTo("other-el");
8334 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8335 el.alignTo("other-el", "tr?");
8337 // align the bottom right corner of el with the center left edge of other-el
8338 el.alignTo("other-el", "br-l?");
8340 // align the center of el with the bottom left corner of other-el and
8341 // adjust the x position by -6 pixels (and the y position by 0)
8342 el.alignTo("other-el", "c-bl", [-6, 0]);
8344 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8345 * @param {String} position The position to align to.
8346 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8347 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8348 * @return {Roo.Element} this
8350 alignTo : function(element, position, offsets, animate){
8351 var xy = this.getAlignToXY(element, position, offsets);
8352 this.setXY(xy, this.preanim(arguments, 3));
8357 * Anchors an element to another element and realigns it when the window is resized.
8358 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8359 * @param {String} position The position to align to.
8360 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8361 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8362 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8363 * is a number, it is used as the buffer delay (defaults to 50ms).
8364 * @param {Function} callback The function to call after the animation finishes
8365 * @return {Roo.Element} this
8367 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8368 var action = function(){
8369 this.alignTo(el, alignment, offsets, animate);
8370 Roo.callback(callback, this);
8372 Roo.EventManager.onWindowResize(action, this);
8373 var tm = typeof monitorScroll;
8374 if(tm != 'undefined'){
8375 Roo.EventManager.on(window, 'scroll', action, this,
8376 {buffer: tm == 'number' ? monitorScroll : 50});
8378 action.call(this); // align immediately
8382 * Clears any opacity settings from this element. Required in some cases for IE.
8383 * @return {Roo.Element} this
8385 clearOpacity : function(){
8386 if (window.ActiveXObject) {
8387 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8388 this.dom.style.filter = "";
8391 this.dom.style.opacity = "";
8392 this.dom.style["-moz-opacity"] = "";
8393 this.dom.style["-khtml-opacity"] = "";
8399 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8400 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8401 * @return {Roo.Element} this
8403 hide : function(animate){
8404 this.setVisible(false, this.preanim(arguments, 0));
8409 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8410 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8411 * @return {Roo.Element} this
8413 show : function(animate){
8414 this.setVisible(true, this.preanim(arguments, 0));
8419 * @private Test if size has a unit, otherwise appends the default
8421 addUnits : function(size){
8422 return Roo.Element.addUnits(size, this.defaultUnit);
8426 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8427 * @return {Roo.Element} this
8429 beginMeasure : function(){
8431 if(el.offsetWidth || el.offsetHeight){
8432 return this; // offsets work already
8435 var p = this.dom, b = document.body; // start with this element
8436 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8437 var pe = Roo.get(p);
8438 if(pe.getStyle('display') == 'none'){
8439 changed.push({el: p, visibility: pe.getStyle("visibility")});
8440 p.style.visibility = "hidden";
8441 p.style.display = "block";
8445 this._measureChanged = changed;
8451 * Restores displays to before beginMeasure was called
8452 * @return {Roo.Element} this
8454 endMeasure : function(){
8455 var changed = this._measureChanged;
8457 for(var i = 0, len = changed.length; i < len; i++) {
8459 r.el.style.visibility = r.visibility;
8460 r.el.style.display = "none";
8462 this._measureChanged = null;
8468 * Update the innerHTML of this element, optionally searching for and processing scripts
8469 * @param {String} html The new HTML
8470 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8471 * @param {Function} callback For async script loading you can be noticed when the update completes
8472 * @return {Roo.Element} this
8474 update : function(html, loadScripts, callback){
8475 if(typeof html == "undefined"){
8478 if(loadScripts !== true){
8479 this.dom.innerHTML = html;
8480 if(typeof callback == "function"){
8488 html += '<span id="' + id + '"></span>';
8490 E.onAvailable(id, function(){
8491 var hd = document.getElementsByTagName("head")[0];
8492 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8493 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8494 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8497 while(match = re.exec(html)){
8498 var attrs = match[1];
8499 var srcMatch = attrs ? attrs.match(srcRe) : false;
8500 if(srcMatch && srcMatch[2]){
8501 var s = document.createElement("script");
8502 s.src = srcMatch[2];
8503 var typeMatch = attrs.match(typeRe);
8504 if(typeMatch && typeMatch[2]){
8505 s.type = typeMatch[2];
8508 }else if(match[2] && match[2].length > 0){
8509 if(window.execScript) {
8510 window.execScript(match[2]);
8518 window.eval(match[2]);
8522 var el = document.getElementById(id);
8523 if(el){el.parentNode.removeChild(el);}
8524 if(typeof callback == "function"){
8528 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8533 * Direct access to the UpdateManager update() method (takes the same parameters).
8534 * @param {String/Function} url The url for this request or a function to call to get the url
8535 * @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}
8536 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8537 * @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.
8538 * @return {Roo.Element} this
8541 var um = this.getUpdateManager();
8542 um.update.apply(um, arguments);
8547 * Gets this element's UpdateManager
8548 * @return {Roo.UpdateManager} The UpdateManager
8550 getUpdateManager : function(){
8551 if(!this.updateManager){
8552 this.updateManager = new Roo.UpdateManager(this);
8554 return this.updateManager;
8558 * Disables text selection for this element (normalized across browsers)
8559 * @return {Roo.Element} this
8561 unselectable : function(){
8562 this.dom.unselectable = "on";
8563 this.swallowEvent("selectstart", true);
8564 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8565 this.addClass("x-unselectable");
8570 * Calculates the x, y to center this element on the screen
8571 * @return {Array} The x, y values [x, y]
8573 getCenterXY : function(){
8574 return this.getAlignToXY(document, 'c-c');
8578 * Centers the Element in either the viewport, or another Element.
8579 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8581 center : function(centerIn){
8582 this.alignTo(centerIn || document, 'c-c');
8587 * Tests various css rules/browsers to determine if this element uses a border box
8590 isBorderBox : function(){
8591 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8595 * Return a box {x, y, width, height} that can be used to set another elements
8596 * size/location to match this element.
8597 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8598 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8599 * @return {Object} box An object in the format {x, y, width, height}
8601 getBox : function(contentBox, local){
8606 var left = parseInt(this.getStyle("left"), 10) || 0;
8607 var top = parseInt(this.getStyle("top"), 10) || 0;
8610 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8612 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8614 var l = this.getBorderWidth("l")+this.getPadding("l");
8615 var r = this.getBorderWidth("r")+this.getPadding("r");
8616 var t = this.getBorderWidth("t")+this.getPadding("t");
8617 var b = this.getBorderWidth("b")+this.getPadding("b");
8618 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)};
8620 bx.right = bx.x + bx.width;
8621 bx.bottom = bx.y + bx.height;
8626 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8627 for more information about the sides.
8628 * @param {String} sides
8631 getFrameWidth : function(sides, onlyContentBox){
8632 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8636 * 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.
8637 * @param {Object} box The box to fill {x, y, width, height}
8638 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8639 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8640 * @return {Roo.Element} this
8642 setBox : function(box, adjust, animate){
8643 var w = box.width, h = box.height;
8644 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8645 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8646 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8648 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8653 * Forces the browser to repaint this element
8654 * @return {Roo.Element} this
8656 repaint : function(){
8658 this.addClass("x-repaint");
8659 setTimeout(function(){
8660 Roo.get(dom).removeClass("x-repaint");
8666 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8667 * then it returns the calculated width of the sides (see getPadding)
8668 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8669 * @return {Object/Number}
8671 getMargins : function(side){
8674 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8675 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8676 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8677 right: parseInt(this.getStyle("margin-right"), 10) || 0
8680 return this.addStyles(side, El.margins);
8685 addStyles : function(sides, styles){
8687 for(var i = 0, len = sides.length; i < len; i++){
8688 v = this.getStyle(styles[sides.charAt(i)]);
8690 w = parseInt(v, 10);
8698 * Creates a proxy element of this element
8699 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8700 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8701 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8702 * @return {Roo.Element} The new proxy element
8704 createProxy : function(config, renderTo, matchBox){
8706 renderTo = Roo.getDom(renderTo);
8708 renderTo = document.body;
8710 config = typeof config == "object" ?
8711 config : {tag : "div", cls: config};
8712 var proxy = Roo.DomHelper.append(renderTo, config, true);
8714 proxy.setBox(this.getBox());
8720 * Puts a mask over this element to disable user interaction. Requires core.css.
8721 * This method can only be applied to elements which accept child nodes.
8722 * @param {String} msg (optional) A message to display in the mask
8723 * @param {String} msgCls (optional) A css class to apply to the msg element
8724 * @return {Element} The mask element
8726 mask : function(msg, msgCls){
8727 if(this.getStyle("position") == "static"){
8728 this.setStyle("position", "relative");
8731 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8733 this.addClass("x-masked");
8734 this._mask.setDisplayed(true);
8735 if(typeof msg == 'string'){
8737 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8739 var mm = this._maskMsg;
8740 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8741 mm.dom.firstChild.innerHTML = msg;
8742 mm.setDisplayed(true);
8745 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8746 this._mask.setHeight(this.getHeight());
8752 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8753 * it is cached for reuse.
8755 unmask : function(removeEl){
8757 if(removeEl === true){
8758 this._mask.remove();
8761 this._maskMsg.remove();
8762 delete this._maskMsg;
8765 this._mask.setDisplayed(false);
8767 this._maskMsg.setDisplayed(false);
8771 this.removeClass("x-masked");
8775 * Returns true if this element is masked
8778 isMasked : function(){
8779 return this._mask && this._mask.isVisible();
8783 * Creates an iframe shim for this element to keep selects and other windowed objects from
8785 * @return {Roo.Element} The new shim element
8787 createShim : function(){
8788 var el = document.createElement('iframe');
8789 el.frameBorder = 'no';
8790 el.className = 'roo-shim';
8791 if(Roo.isIE && Roo.isSecure){
8792 el.src = Roo.SSL_SECURE_URL;
8794 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8795 shim.autoBoxAdjust = false;
8800 * Removes this element from the DOM and deletes it from the cache
8802 remove : function(){
8803 if(this.dom.parentNode){
8804 this.dom.parentNode.removeChild(this.dom);
8806 delete El.cache[this.dom.id];
8810 * Sets up event handlers to add and remove a css class when the mouse is over this element
8811 * @param {String} className
8812 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8813 * mouseout events for children elements
8814 * @return {Roo.Element} this
8816 addClassOnOver : function(className, preventFlicker){
8817 this.on("mouseover", function(){
8818 Roo.fly(this, '_internal').addClass(className);
8820 var removeFn = function(e){
8821 if(preventFlicker !== true || !e.within(this, true)){
8822 Roo.fly(this, '_internal').removeClass(className);
8825 this.on("mouseout", removeFn, this.dom);
8830 * Sets up event handlers to add and remove a css class when this element has the focus
8831 * @param {String} className
8832 * @return {Roo.Element} this
8834 addClassOnFocus : function(className){
8835 this.on("focus", function(){
8836 Roo.fly(this, '_internal').addClass(className);
8838 this.on("blur", function(){
8839 Roo.fly(this, '_internal').removeClass(className);
8844 * 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)
8845 * @param {String} className
8846 * @return {Roo.Element} this
8848 addClassOnClick : function(className){
8850 this.on("mousedown", function(){
8851 Roo.fly(dom, '_internal').addClass(className);
8852 var d = Roo.get(document);
8853 var fn = function(){
8854 Roo.fly(dom, '_internal').removeClass(className);
8855 d.removeListener("mouseup", fn);
8857 d.on("mouseup", fn);
8863 * Stops the specified event from bubbling and optionally prevents the default action
8864 * @param {String} eventName
8865 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8866 * @return {Roo.Element} this
8868 swallowEvent : function(eventName, preventDefault){
8869 var fn = function(e){
8870 e.stopPropagation();
8875 if(eventName instanceof Array){
8876 for(var i = 0, len = eventName.length; i < len; i++){
8877 this.on(eventName[i], fn);
8881 this.on(eventName, fn);
8888 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8891 * Sizes this element to its parent element's dimensions performing
8892 * neccessary box adjustments.
8893 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8894 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8895 * @return {Roo.Element} this
8897 fitToParent : function(monitorResize, targetParent) {
8898 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8899 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8900 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8903 var p = Roo.get(targetParent || this.dom.parentNode);
8904 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8905 if (monitorResize === true) {
8906 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8907 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8913 * Gets the next sibling, skipping text nodes
8914 * @return {HTMLElement} The next sibling or null
8916 getNextSibling : function(){
8917 var n = this.dom.nextSibling;
8918 while(n && n.nodeType != 1){
8925 * Gets the previous sibling, skipping text nodes
8926 * @return {HTMLElement} The previous sibling or null
8928 getPrevSibling : function(){
8929 var n = this.dom.previousSibling;
8930 while(n && n.nodeType != 1){
8931 n = n.previousSibling;
8938 * Appends the passed element(s) to this element
8939 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8940 * @return {Roo.Element} this
8942 appendChild: function(el){
8949 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8950 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8951 * automatically generated with the specified attributes.
8952 * @param {HTMLElement} insertBefore (optional) a child element of this element
8953 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8954 * @return {Roo.Element} The new child element
8956 createChild: function(config, insertBefore, returnDom){
8957 config = config || {tag:'div'};
8959 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8961 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8965 * Appends this element to the passed element
8966 * @param {String/HTMLElement/Element} el The new parent element
8967 * @return {Roo.Element} this
8969 appendTo: function(el){
8970 el = Roo.getDom(el);
8971 el.appendChild(this.dom);
8976 * Inserts this element before the passed element in the DOM
8977 * @param {String/HTMLElement/Element} el The element to insert before
8978 * @return {Roo.Element} this
8980 insertBefore: function(el){
8981 el = Roo.getDom(el);
8982 el.parentNode.insertBefore(this.dom, el);
8987 * Inserts this element after the passed element in the DOM
8988 * @param {String/HTMLElement/Element} el The element to insert after
8989 * @return {Roo.Element} this
8991 insertAfter: function(el){
8992 el = Roo.getDom(el);
8993 el.parentNode.insertBefore(this.dom, el.nextSibling);
8998 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8999 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9000 * @return {Roo.Element} The new child
9002 insertFirst: function(el, returnDom){
9004 if(typeof el == 'object' && !el.nodeType){ // dh config
9005 return this.createChild(el, this.dom.firstChild, returnDom);
9007 el = Roo.getDom(el);
9008 this.dom.insertBefore(el, this.dom.firstChild);
9009 return !returnDom ? Roo.get(el) : el;
9014 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9015 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9016 * @param {String} where (optional) 'before' or 'after' defaults to before
9017 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9018 * @return {Roo.Element} the inserted Element
9020 insertSibling: function(el, where, returnDom){
9021 where = where ? where.toLowerCase() : 'before';
9023 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9025 if(typeof el == 'object' && !el.nodeType){ // dh config
9026 if(where == 'after' && !this.dom.nextSibling){
9027 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9029 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9033 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9034 where == 'before' ? this.dom : this.dom.nextSibling);
9043 * Creates and wraps this element with another element
9044 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9045 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9046 * @return {HTMLElement/Element} The newly created wrapper element
9048 wrap: function(config, returnDom){
9050 config = {tag: "div"};
9052 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9053 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9058 * Replaces the passed element with this element
9059 * @param {String/HTMLElement/Element} el The element to replace
9060 * @return {Roo.Element} this
9062 replace: function(el){
9064 this.insertBefore(el);
9070 * Inserts an html fragment into this element
9071 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9072 * @param {String} html The HTML fragment
9073 * @param {Boolean} returnEl True to return an Roo.Element
9074 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9076 insertHtml : function(where, html, returnEl){
9077 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9078 return returnEl ? Roo.get(el) : el;
9082 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9083 * @param {Object} o The object with the attributes
9084 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9085 * @return {Roo.Element} this
9087 set : function(o, useSet){
9089 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9091 if(attr == "style" || typeof o[attr] == "function") continue;
9093 el.className = o["cls"];
9095 if(useSet) el.setAttribute(attr, o[attr]);
9096 else el[attr] = o[attr];
9100 Roo.DomHelper.applyStyles(el, o.style);
9106 * Convenience method for constructing a KeyMap
9107 * @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:
9108 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9109 * @param {Function} fn The function to call
9110 * @param {Object} scope (optional) The scope of the function
9111 * @return {Roo.KeyMap} The KeyMap created
9113 addKeyListener : function(key, fn, scope){
9115 if(typeof key != "object" || key instanceof Array){
9131 return new Roo.KeyMap(this, config);
9135 * Creates a KeyMap for this element
9136 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9137 * @return {Roo.KeyMap} The KeyMap created
9139 addKeyMap : function(config){
9140 return new Roo.KeyMap(this, config);
9144 * Returns true if this element is scrollable.
9147 isScrollable : function(){
9149 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9153 * 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().
9154 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9155 * @param {Number} value The new scroll value
9156 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9157 * @return {Element} this
9160 scrollTo : function(side, value, animate){
9161 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9163 this.dom[prop] = value;
9165 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9166 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9172 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9173 * within this element's scrollable range.
9174 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9175 * @param {Number} distance How far to scroll the element in pixels
9176 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9177 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9178 * was scrolled as far as it could go.
9180 scroll : function(direction, distance, animate){
9181 if(!this.isScrollable()){
9185 var l = el.scrollLeft, t = el.scrollTop;
9186 var w = el.scrollWidth, h = el.scrollHeight;
9187 var cw = el.clientWidth, ch = el.clientHeight;
9188 direction = direction.toLowerCase();
9189 var scrolled = false;
9190 var a = this.preanim(arguments, 2);
9195 var v = Math.min(l + distance, w-cw);
9196 this.scrollTo("left", v, a);
9203 var v = Math.max(l - distance, 0);
9204 this.scrollTo("left", v, a);
9212 var v = Math.max(t - distance, 0);
9213 this.scrollTo("top", v, a);
9221 var v = Math.min(t + distance, h-ch);
9222 this.scrollTo("top", v, a);
9231 * Translates the passed page coordinates into left/top css values for this element
9232 * @param {Number/Array} x The page x or an array containing [x, y]
9233 * @param {Number} y The page y
9234 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9236 translatePoints : function(x, y){
9237 if(typeof x == 'object' || x instanceof Array){
9240 var p = this.getStyle('position');
9241 var o = this.getXY();
9243 var l = parseInt(this.getStyle('left'), 10);
9244 var t = parseInt(this.getStyle('top'), 10);
9247 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9250 t = (p == "relative") ? 0 : this.dom.offsetTop;
9253 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9257 * Returns the current scroll position of the element.
9258 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9260 getScroll : function(){
9261 var d = this.dom, doc = document;
9262 if(d == doc || d == doc.body){
9263 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9264 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9265 return {left: l, top: t};
9267 return {left: d.scrollLeft, top: d.scrollTop};
9272 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9273 * are convert to standard 6 digit hex color.
9274 * @param {String} attr The css attribute
9275 * @param {String} defaultValue The default value to use when a valid color isn't found
9276 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9279 getColor : function(attr, defaultValue, prefix){
9280 var v = this.getStyle(attr);
9281 if(!v || v == "transparent" || v == "inherit") {
9282 return defaultValue;
9284 var color = typeof prefix == "undefined" ? "#" : prefix;
9285 if(v.substr(0, 4) == "rgb("){
9286 var rvs = v.slice(4, v.length -1).split(",");
9287 for(var i = 0; i < 3; i++){
9288 var h = parseInt(rvs[i]).toString(16);
9295 if(v.substr(0, 1) == "#"){
9297 for(var i = 1; i < 4; i++){
9298 var c = v.charAt(i);
9301 }else if(v.length == 7){
9302 color += v.substr(1);
9306 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9310 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9311 * gradient background, rounded corners and a 4-way shadow.
9312 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9313 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9314 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9315 * @return {Roo.Element} this
9317 boxWrap : function(cls){
9318 cls = cls || 'x-box';
9319 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9320 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9325 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9326 * @param {String} namespace The namespace in which to look for the attribute
9327 * @param {String} name The attribute name
9328 * @return {String} The attribute value
9330 getAttributeNS : Roo.isIE ? function(ns, name){
9332 var type = typeof d[ns+":"+name];
9333 if(type != 'undefined' && type != 'unknown'){
9334 return d[ns+":"+name];
9337 } : function(ns, name){
9339 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9343 var ep = El.prototype;
9346 * Appends an event handler (Shorthand for addListener)
9347 * @param {String} eventName The type of event to append
9348 * @param {Function} fn The method the event invokes
9349 * @param {Object} scope (optional) The scope (this object) of the fn
9350 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9353 ep.on = ep.addListener;
9355 ep.mon = ep.addListener;
9358 * Removes an event handler from this element (shorthand for removeListener)
9359 * @param {String} eventName the type of event to remove
9360 * @param {Function} fn the method the event invokes
9361 * @return {Roo.Element} this
9364 ep.un = ep.removeListener;
9367 * true to automatically adjust width and height settings for box-model issues (default to true)
9369 ep.autoBoxAdjust = true;
9372 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9375 El.addUnits = function(v, defaultUnit){
9376 if(v === "" || v == "auto"){
9379 if(v === undefined){
9382 if(typeof v == "number" || !El.unitPattern.test(v)){
9383 return v + (defaultUnit || 'px');
9388 // special markup used throughout Roo when box wrapping elements
9389 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>';
9391 * Visibility mode constant - Use visibility to hide element
9397 * Visibility mode constant - Use display to hide element
9403 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9404 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9405 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9417 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9418 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9419 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9420 * @return {Element} The Element object
9423 El.get = function(el){
9425 if(!el){ return null; }
9426 if(typeof el == "string"){ // element id
9427 if(!(elm = document.getElementById(el))){
9430 if(ex = El.cache[el]){
9433 ex = El.cache[el] = new El(elm);
9436 }else if(el.tagName){ // dom element
9440 if(ex = El.cache[id]){
9443 ex = El.cache[id] = new El(el);
9446 }else if(el instanceof El){
9448 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9449 // catch case where it hasn't been appended
9450 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9453 }else if(el.isComposite){
9455 }else if(el instanceof Array){
9456 return El.select(el);
9457 }else if(el == document){
9458 // create a bogus element object representing the document object
9460 var f = function(){};
9461 f.prototype = El.prototype;
9463 docEl.dom = document;
9471 El.uncache = function(el){
9472 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9474 delete El.cache[a[i].id || a[i]];
9480 // Garbage collection - uncache elements/purge listeners on orphaned elements
9481 // so we don't hold a reference and cause the browser to retain them
9482 El.garbageCollect = function(){
9483 if(!Roo.enableGarbageCollector){
9484 clearInterval(El.collectorThread);
9487 for(var eid in El.cache){
9488 var el = El.cache[eid], d = el.dom;
9489 // -------------------------------------------------------
9490 // Determining what is garbage:
9491 // -------------------------------------------------------
9493 // dom node is null, definitely garbage
9494 // -------------------------------------------------------
9496 // no parentNode == direct orphan, definitely garbage
9497 // -------------------------------------------------------
9498 // !d.offsetParent && !document.getElementById(eid)
9499 // display none elements have no offsetParent so we will
9500 // also try to look it up by it's id. However, check
9501 // offsetParent first so we don't do unneeded lookups.
9502 // This enables collection of elements that are not orphans
9503 // directly, but somewhere up the line they have an orphan
9505 // -------------------------------------------------------
9506 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9507 delete El.cache[eid];
9508 if(d && Roo.enableListenerCollection){
9514 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9518 El.Flyweight = function(dom){
9521 El.Flyweight.prototype = El.prototype;
9523 El._flyweights = {};
9525 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9526 * the dom node can be overwritten by other code.
9527 * @param {String/HTMLElement} el The dom node or id
9528 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9529 * prevent conflicts (e.g. internally Roo uses "_internal")
9531 * @return {Element} The shared Element object
9533 El.fly = function(el, named){
9534 named = named || '_global';
9535 el = Roo.getDom(el);
9539 if(!El._flyweights[named]){
9540 El._flyweights[named] = new El.Flyweight();
9542 El._flyweights[named].dom = el;
9543 return El._flyweights[named];
9547 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9548 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9549 * Shorthand of {@link Roo.Element#get}
9550 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9551 * @return {Element} The Element object
9557 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9558 * the dom node can be overwritten by other code.
9559 * Shorthand of {@link Roo.Element#fly}
9560 * @param {String/HTMLElement} el The dom node or id
9561 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9562 * prevent conflicts (e.g. internally Roo uses "_internal")
9564 * @return {Element} The shared Element object
9570 // speedy lookup for elements never to box adjust
9571 var noBoxAdjust = Roo.isStrict ? {
9574 input:1, select:1, textarea:1
9576 if(Roo.isIE || Roo.isGecko){
9577 noBoxAdjust['button'] = 1;
9581 Roo.EventManager.on(window, 'unload', function(){
9583 delete El._flyweights;
9591 Roo.Element.selectorFunction = Roo.DomQuery.select;
9594 Roo.Element.select = function(selector, unique, root){
9596 if(typeof selector == "string"){
9597 els = Roo.Element.selectorFunction(selector, root);
9598 }else if(selector.length !== undefined){
9601 throw "Invalid selector";
9603 if(unique === true){
9604 return new Roo.CompositeElement(els);
9606 return new Roo.CompositeElementLite(els);
9610 * Selects elements based on the passed CSS selector to enable working on them as 1.
9611 * @param {String/Array} selector The CSS selector or an array of elements
9612 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9613 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9614 * @return {CompositeElementLite/CompositeElement}
9618 Roo.select = Roo.Element.select;
9635 * Ext JS Library 1.1.1
9636 * Copyright(c) 2006-2007, Ext JS, LLC.
9638 * Originally Released Under LGPL - original licence link has changed is not relivant.
9641 * <script type="text/javascript">
9646 //Notifies Element that fx methods are available
9647 Roo.enableFx = true;
9651 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9652 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9653 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9654 * Element effects to work.</p><br/>
9656 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9657 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9658 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9659 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9660 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9661 * expected results and should be done with care.</p><br/>
9663 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9664 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9667 ----- -----------------------------
9668 tl The top left corner
9669 t The center of the top edge
9670 tr The top right corner
9671 l The center of the left edge
9672 r The center of the right edge
9673 bl The bottom left corner
9674 b The center of the bottom edge
9675 br The bottom right corner
9677 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9678 * below are common options that can be passed to any Fx method.</b>
9679 * @cfg {Function} callback A function called when the effect is finished
9680 * @cfg {Object} scope The scope of the effect function
9681 * @cfg {String} easing A valid Easing value for the effect
9682 * @cfg {String} afterCls A css class to apply after the effect
9683 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9684 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9685 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9686 * effects that end with the element being visually hidden, ignored otherwise)
9687 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9688 * a function which returns such a specification that will be applied to the Element after the effect finishes
9689 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9690 * @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
9691 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9695 * Slides the element into view. An anchor point can be optionally passed to set the point of
9696 * origin for the slide effect. This function automatically handles wrapping the element with
9697 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9700 // default: slide the element in from the top
9703 // custom: slide the element in from the right with a 2-second duration
9704 el.slideIn('r', { duration: 2 });
9706 // common config options shown with default values
9712 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9713 * @param {Object} options (optional) Object literal with any of the Fx config options
9714 * @return {Roo.Element} The Element
9716 slideIn : function(anchor, o){
9717 var el = this.getFxEl();
9720 el.queueFx(o, function(){
9722 anchor = anchor || "t";
9724 // fix display to visibility
9727 // restore values after effect
9728 var r = this.getFxRestore();
9729 var b = this.getBox();
9730 // fixed size for slide
9734 var wrap = this.fxWrap(r.pos, o, "hidden");
9736 var st = this.dom.style;
9737 st.visibility = "visible";
9738 st.position = "absolute";
9740 // clear out temp styles after slide and unwrap
9741 var after = function(){
9742 el.fxUnwrap(wrap, r.pos, o);
9744 st.height = r.height;
9747 // time to calc the positions
9748 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9750 switch(anchor.toLowerCase()){
9752 wrap.setSize(b.width, 0);
9753 st.left = st.bottom = "0";
9757 wrap.setSize(0, b.height);
9758 st.right = st.top = "0";
9762 wrap.setSize(0, b.height);
9764 st.left = st.top = "0";
9765 a = {width: bw, points: pt};
9768 wrap.setSize(b.width, 0);
9769 wrap.setY(b.bottom);
9770 st.left = st.top = "0";
9771 a = {height: bh, points: pt};
9775 st.right = st.bottom = "0";
9776 a = {width: bw, height: bh};
9780 wrap.setY(b.y+b.height);
9781 st.right = st.top = "0";
9782 a = {width: bw, height: bh, points: pt};
9786 wrap.setXY([b.right, b.bottom]);
9787 st.left = st.top = "0";
9788 a = {width: bw, height: bh, points: pt};
9792 wrap.setX(b.x+b.width);
9793 st.left = st.bottom = "0";
9794 a = {width: bw, height: bh, points: pt};
9797 this.dom.style.visibility = "visible";
9800 arguments.callee.anim = wrap.fxanim(a,
9810 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9811 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9812 * 'hidden') but block elements will still take up space in the document. The element must be removed
9813 * from the DOM using the 'remove' config option if desired. This function automatically handles
9814 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9817 // default: slide the element out to the top
9820 // custom: slide the element out to the right with a 2-second duration
9821 el.slideOut('r', { duration: 2 });
9823 // common config options shown with default values
9831 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9832 * @param {Object} options (optional) Object literal with any of the Fx config options
9833 * @return {Roo.Element} The Element
9835 slideOut : function(anchor, o){
9836 var el = this.getFxEl();
9839 el.queueFx(o, function(){
9841 anchor = anchor || "t";
9843 // restore values after effect
9844 var r = this.getFxRestore();
9846 var b = this.getBox();
9847 // fixed size for slide
9851 var wrap = this.fxWrap(r.pos, o, "visible");
9853 var st = this.dom.style;
9854 st.visibility = "visible";
9855 st.position = "absolute";
9859 var after = function(){
9861 el.setDisplayed(false);
9866 el.fxUnwrap(wrap, r.pos, o);
9869 st.height = r.height;
9874 var a, zero = {to: 0};
9875 switch(anchor.toLowerCase()){
9877 st.left = st.bottom = "0";
9881 st.right = st.top = "0";
9885 st.left = st.top = "0";
9886 a = {width: zero, points: {to:[b.right, b.y]}};
9889 st.left = st.top = "0";
9890 a = {height: zero, points: {to:[b.x, b.bottom]}};
9893 st.right = st.bottom = "0";
9894 a = {width: zero, height: zero};
9897 st.right = st.top = "0";
9898 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9901 st.left = st.top = "0";
9902 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9905 st.left = st.bottom = "0";
9906 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9910 arguments.callee.anim = wrap.fxanim(a,
9920 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9921 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9922 * The element must be removed from the DOM using the 'remove' config option if desired.
9928 // common config options shown with default values
9936 * @param {Object} options (optional) Object literal with any of the Fx config options
9937 * @return {Roo.Element} The Element
9940 var el = this.getFxEl();
9943 el.queueFx(o, function(){
9944 this.clearOpacity();
9947 // restore values after effect
9948 var r = this.getFxRestore();
9949 var st = this.dom.style;
9951 var after = function(){
9953 el.setDisplayed(false);
9960 el.setPositioning(r.pos);
9962 st.height = r.height;
9967 var width = this.getWidth();
9968 var height = this.getHeight();
9970 arguments.callee.anim = this.fxanim({
9971 width : {to: this.adjustWidth(width * 2)},
9972 height : {to: this.adjustHeight(height * 2)},
9973 points : {by: [-(width * .5), -(height * .5)]},
9975 fontSize: {to:200, unit: "%"}
9986 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9987 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
9988 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9994 // all config options shown with default values
10002 * @param {Object} options (optional) Object literal with any of the Fx config options
10003 * @return {Roo.Element} The Element
10005 switchOff : function(o){
10006 var el = this.getFxEl();
10009 el.queueFx(o, function(){
10010 this.clearOpacity();
10013 // restore values after effect
10014 var r = this.getFxRestore();
10015 var st = this.dom.style;
10017 var after = function(){
10019 el.setDisplayed(false);
10025 el.setPositioning(r.pos);
10026 st.width = r.width;
10027 st.height = r.height;
10032 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10033 this.clearOpacity();
10037 points:{by:[0, this.getHeight() * .5]}
10038 }, o, 'motion', 0.3, 'easeIn', after);
10039 }).defer(100, this);
10046 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10047 * changed using the "attr" config option) and then fading back to the original color. If no original
10048 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10051 // default: highlight background to yellow
10054 // custom: highlight foreground text to blue for 2 seconds
10055 el.highlight("0000ff", { attr: 'color', duration: 2 });
10057 // common config options shown with default values
10058 el.highlight("ffff9c", {
10059 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10060 endColor: (current color) or "ffffff",
10065 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10066 * @param {Object} options (optional) Object literal with any of the Fx config options
10067 * @return {Roo.Element} The Element
10069 highlight : function(color, o){
10070 var el = this.getFxEl();
10073 el.queueFx(o, function(){
10074 color = color || "ffff9c";
10075 attr = o.attr || "backgroundColor";
10077 this.clearOpacity();
10080 var origColor = this.getColor(attr);
10081 var restoreColor = this.dom.style[attr];
10082 endColor = (o.endColor || origColor) || "ffffff";
10084 var after = function(){
10085 el.dom.style[attr] = restoreColor;
10090 a[attr] = {from: color, to: endColor};
10091 arguments.callee.anim = this.fxanim(a,
10101 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10104 // default: a single light blue ripple
10107 // custom: 3 red ripples lasting 3 seconds total
10108 el.frame("ff0000", 3, { duration: 3 });
10110 // common config options shown with default values
10111 el.frame("C3DAF9", 1, {
10112 duration: 1 //duration of entire animation (not each individual ripple)
10113 // Note: Easing is not configurable and will be ignored if included
10116 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10117 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10118 * @param {Object} options (optional) Object literal with any of the Fx config options
10119 * @return {Roo.Element} The Element
10121 frame : function(color, count, o){
10122 var el = this.getFxEl();
10125 el.queueFx(o, function(){
10126 color = color || "#C3DAF9";
10127 if(color.length == 6){
10128 color = "#" + color;
10130 count = count || 1;
10131 duration = o.duration || 1;
10134 var b = this.getBox();
10135 var animFn = function(){
10136 var proxy = this.createProxy({
10139 visbility:"hidden",
10140 position:"absolute",
10141 "z-index":"35000", // yee haw
10142 border:"0px solid " + color
10145 var scale = Roo.isBorderBox ? 2 : 1;
10147 top:{from:b.y, to:b.y - 20},
10148 left:{from:b.x, to:b.x - 20},
10149 borderWidth:{from:0, to:10},
10150 opacity:{from:1, to:0},
10151 height:{from:b.height, to:(b.height + (20*scale))},
10152 width:{from:b.width, to:(b.width + (20*scale))}
10153 }, duration, function(){
10157 animFn.defer((duration/2)*1000, this);
10168 * Creates a pause before any subsequent queued effects begin. If there are
10169 * no effects queued after the pause it will have no effect.
10174 * @param {Number} seconds The length of time to pause (in seconds)
10175 * @return {Roo.Element} The Element
10177 pause : function(seconds){
10178 var el = this.getFxEl();
10181 el.queueFx(o, function(){
10182 setTimeout(function(){
10184 }, seconds * 1000);
10190 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10191 * using the "endOpacity" config option.
10194 // default: fade in from opacity 0 to 100%
10197 // custom: fade in from opacity 0 to 75% over 2 seconds
10198 el.fadeIn({ endOpacity: .75, duration: 2});
10200 // common config options shown with default values
10202 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10207 * @param {Object} options (optional) Object literal with any of the Fx config options
10208 * @return {Roo.Element} The Element
10210 fadeIn : function(o){
10211 var el = this.getFxEl();
10213 el.queueFx(o, function(){
10214 this.setOpacity(0);
10216 this.dom.style.visibility = 'visible';
10217 var to = o.endOpacity || 1;
10218 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10219 o, null, .5, "easeOut", function(){
10221 this.clearOpacity();
10230 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10231 * using the "endOpacity" config option.
10234 // default: fade out from the element's current opacity to 0
10237 // custom: fade out from the element's current opacity to 25% over 2 seconds
10238 el.fadeOut({ endOpacity: .25, duration: 2});
10240 // common config options shown with default values
10242 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10249 * @param {Object} options (optional) Object literal with any of the Fx config options
10250 * @return {Roo.Element} The Element
10252 fadeOut : function(o){
10253 var el = this.getFxEl();
10255 el.queueFx(o, function(){
10256 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10257 o, null, .5, "easeOut", function(){
10258 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10259 this.dom.style.display = "none";
10261 this.dom.style.visibility = "hidden";
10263 this.clearOpacity();
10271 * Animates the transition of an element's dimensions from a starting height/width
10272 * to an ending height/width.
10275 // change height and width to 100x100 pixels
10276 el.scale(100, 100);
10278 // common config options shown with default values. The height and width will default to
10279 // the element's existing values if passed as null.
10282 [element's height], {
10287 * @param {Number} width The new width (pass undefined to keep the original width)
10288 * @param {Number} height The new height (pass undefined to keep the original height)
10289 * @param {Object} options (optional) Object literal with any of the Fx config options
10290 * @return {Roo.Element} The Element
10292 scale : function(w, h, o){
10293 this.shift(Roo.apply({}, o, {
10301 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10302 * Any of these properties not specified in the config object will not be changed. This effect
10303 * requires that at least one new dimension, position or opacity setting must be passed in on
10304 * the config object in order for the function to have any effect.
10307 // slide the element horizontally to x position 200 while changing the height and opacity
10308 el.shift({ x: 200, height: 50, opacity: .8 });
10310 // common config options shown with default values.
10312 width: [element's width],
10313 height: [element's height],
10314 x: [element's x position],
10315 y: [element's y position],
10316 opacity: [element's opacity],
10321 * @param {Object} options Object literal with any of the Fx config options
10322 * @return {Roo.Element} The Element
10324 shift : function(o){
10325 var el = this.getFxEl();
10327 el.queueFx(o, function(){
10328 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10329 if(w !== undefined){
10330 a.width = {to: this.adjustWidth(w)};
10332 if(h !== undefined){
10333 a.height = {to: this.adjustHeight(h)};
10335 if(x !== undefined || y !== undefined){
10337 x !== undefined ? x : this.getX(),
10338 y !== undefined ? y : this.getY()
10341 if(op !== undefined){
10342 a.opacity = {to: op};
10344 if(o.xy !== undefined){
10345 a.points = {to: o.xy};
10347 arguments.callee.anim = this.fxanim(a,
10348 o, 'motion', .35, "easeOut", function(){
10356 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10357 * ending point of the effect.
10360 // default: slide the element downward while fading out
10363 // custom: slide the element out to the right with a 2-second duration
10364 el.ghost('r', { duration: 2 });
10366 // common config options shown with default values
10374 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10375 * @param {Object} options (optional) Object literal with any of the Fx config options
10376 * @return {Roo.Element} The Element
10378 ghost : function(anchor, o){
10379 var el = this.getFxEl();
10382 el.queueFx(o, function(){
10383 anchor = anchor || "b";
10385 // restore values after effect
10386 var r = this.getFxRestore();
10387 var w = this.getWidth(),
10388 h = this.getHeight();
10390 var st = this.dom.style;
10392 var after = function(){
10394 el.setDisplayed(false);
10400 el.setPositioning(r.pos);
10401 st.width = r.width;
10402 st.height = r.height;
10407 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10408 switch(anchor.toLowerCase()){
10435 arguments.callee.anim = this.fxanim(a,
10445 * Ensures that all effects queued after syncFx is called on the element are
10446 * run concurrently. This is the opposite of {@link #sequenceFx}.
10447 * @return {Roo.Element} The Element
10449 syncFx : function(){
10450 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10459 * Ensures that all effects queued after sequenceFx is called on the element are
10460 * run in sequence. This is the opposite of {@link #syncFx}.
10461 * @return {Roo.Element} The Element
10463 sequenceFx : function(){
10464 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10466 concurrent : false,
10473 nextFx : function(){
10474 var ef = this.fxQueue[0];
10481 * Returns true if the element has any effects actively running or queued, else returns false.
10482 * @return {Boolean} True if element has active effects, else false
10484 hasActiveFx : function(){
10485 return this.fxQueue && this.fxQueue[0];
10489 * Stops any running effects and clears the element's internal effects queue if it contains
10490 * any additional effects that haven't started yet.
10491 * @return {Roo.Element} The Element
10493 stopFx : function(){
10494 if(this.hasActiveFx()){
10495 var cur = this.fxQueue[0];
10496 if(cur && cur.anim && cur.anim.isAnimated()){
10497 this.fxQueue = [cur]; // clear out others
10498 cur.anim.stop(true);
10505 beforeFx : function(o){
10506 if(this.hasActiveFx() && !o.concurrent){
10517 * Returns true if the element is currently blocking so that no other effect can be queued
10518 * until this effect is finished, else returns false if blocking is not set. This is commonly
10519 * used to ensure that an effect initiated by a user action runs to completion prior to the
10520 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10521 * @return {Boolean} True if blocking, else false
10523 hasFxBlock : function(){
10524 var q = this.fxQueue;
10525 return q && q[0] && q[0].block;
10529 queueFx : function(o, fn){
10533 if(!this.hasFxBlock()){
10534 Roo.applyIf(o, this.fxDefaults);
10536 var run = this.beforeFx(o);
10537 fn.block = o.block;
10538 this.fxQueue.push(fn);
10550 fxWrap : function(pos, o, vis){
10552 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10555 wrapXY = this.getXY();
10557 var div = document.createElement("div");
10558 div.style.visibility = vis;
10559 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10560 wrap.setPositioning(pos);
10561 if(wrap.getStyle("position") == "static"){
10562 wrap.position("relative");
10564 this.clearPositioning('auto');
10566 wrap.dom.appendChild(this.dom);
10568 wrap.setXY(wrapXY);
10575 fxUnwrap : function(wrap, pos, o){
10576 this.clearPositioning();
10577 this.setPositioning(pos);
10579 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10585 getFxRestore : function(){
10586 var st = this.dom.style;
10587 return {pos: this.getPositioning(), width: st.width, height : st.height};
10591 afterFx : function(o){
10593 this.applyStyles(o.afterStyle);
10596 this.addClass(o.afterCls);
10598 if(o.remove === true){
10601 Roo.callback(o.callback, o.scope, [this]);
10603 this.fxQueue.shift();
10609 getFxEl : function(){ // support for composite element fx
10610 return Roo.get(this.dom);
10614 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10615 animType = animType || 'run';
10617 var anim = Roo.lib.Anim[animType](
10619 (opt.duration || defaultDur) || .35,
10620 (opt.easing || defaultEase) || 'easeOut',
10622 Roo.callback(cb, this);
10631 // backwords compat
10632 Roo.Fx.resize = Roo.Fx.scale;
10634 //When included, Roo.Fx is automatically applied to Element so that all basic
10635 //effects are available directly via the Element API
10636 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10638 * Ext JS Library 1.1.1
10639 * Copyright(c) 2006-2007, Ext JS, LLC.
10641 * Originally Released Under LGPL - original licence link has changed is not relivant.
10644 * <script type="text/javascript">
10649 * @class Roo.CompositeElement
10650 * Standard composite class. Creates a Roo.Element for every element in the collection.
10652 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10653 * actions will be performed on all the elements in this collection.</b>
10655 * All methods return <i>this</i> and can be chained.
10657 var els = Roo.select("#some-el div.some-class", true);
10658 // or select directly from an existing element
10659 var el = Roo.get('some-el');
10660 el.select('div.some-class', true);
10662 els.setWidth(100); // all elements become 100 width
10663 els.hide(true); // all elements fade out and hide
10665 els.setWidth(100).hide(true);
10668 Roo.CompositeElement = function(els){
10669 this.elements = [];
10670 this.addElements(els);
10672 Roo.CompositeElement.prototype = {
10674 addElements : function(els){
10675 if(!els) return this;
10676 if(typeof els == "string"){
10677 els = Roo.Element.selectorFunction(els);
10679 var yels = this.elements;
10680 var index = yels.length-1;
10681 for(var i = 0, len = els.length; i < len; i++) {
10682 yels[++index] = Roo.get(els[i]);
10688 * Clears this composite and adds the elements returned by the passed selector.
10689 * @param {String/Array} els A string CSS selector, an array of elements or an element
10690 * @return {CompositeElement} this
10692 fill : function(els){
10693 this.elements = [];
10699 * Filters this composite to only elements that match the passed selector.
10700 * @param {String} selector A string CSS selector
10701 * @return {CompositeElement} this
10703 filter : function(selector){
10705 this.each(function(el){
10706 if(el.is(selector)){
10707 els[els.length] = el.dom;
10714 invoke : function(fn, args){
10715 var els = this.elements;
10716 for(var i = 0, len = els.length; i < len; i++) {
10717 Roo.Element.prototype[fn].apply(els[i], args);
10722 * Adds elements to this composite.
10723 * @param {String/Array} els A string CSS selector, an array of elements or an element
10724 * @return {CompositeElement} this
10726 add : function(els){
10727 if(typeof els == "string"){
10728 this.addElements(Roo.Element.selectorFunction(els));
10729 }else if(els.length !== undefined){
10730 this.addElements(els);
10732 this.addElements([els]);
10737 * Calls the passed function passing (el, this, index) for each element in this composite.
10738 * @param {Function} fn The function to call
10739 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10740 * @return {CompositeElement} this
10742 each : function(fn, scope){
10743 var els = this.elements;
10744 for(var i = 0, len = els.length; i < len; i++){
10745 if(fn.call(scope || els[i], els[i], this, i) === false) {
10753 * Returns the Element object at the specified index
10754 * @param {Number} index
10755 * @return {Roo.Element}
10757 item : function(index){
10758 return this.elements[index] || null;
10762 * Returns the first Element
10763 * @return {Roo.Element}
10765 first : function(){
10766 return this.item(0);
10770 * Returns the last Element
10771 * @return {Roo.Element}
10774 return this.item(this.elements.length-1);
10778 * Returns the number of elements in this composite
10781 getCount : function(){
10782 return this.elements.length;
10786 * Returns true if this composite contains the passed element
10789 contains : function(el){
10790 return this.indexOf(el) !== -1;
10794 * Returns true if this composite contains the passed element
10797 indexOf : function(el){
10798 return this.elements.indexOf(Roo.get(el));
10803 * Removes the specified element(s).
10804 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10805 * or an array of any of those.
10806 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10807 * @return {CompositeElement} this
10809 removeElement : function(el, removeDom){
10810 if(el instanceof Array){
10811 for(var i = 0, len = el.length; i < len; i++){
10812 this.removeElement(el[i]);
10816 var index = typeof el == 'number' ? el : this.indexOf(el);
10819 var d = this.elements[index];
10823 d.parentNode.removeChild(d);
10826 this.elements.splice(index, 1);
10832 * Replaces the specified element with the passed element.
10833 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10835 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10836 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10837 * @return {CompositeElement} this
10839 replaceElement : function(el, replacement, domReplace){
10840 var index = typeof el == 'number' ? el : this.indexOf(el);
10843 this.elements[index].replaceWith(replacement);
10845 this.elements.splice(index, 1, Roo.get(replacement))
10852 * Removes all elements.
10854 clear : function(){
10855 this.elements = [];
10859 Roo.CompositeElement.createCall = function(proto, fnName){
10860 if(!proto[fnName]){
10861 proto[fnName] = function(){
10862 return this.invoke(fnName, arguments);
10866 for(var fnName in Roo.Element.prototype){
10867 if(typeof Roo.Element.prototype[fnName] == "function"){
10868 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10874 * Ext JS Library 1.1.1
10875 * Copyright(c) 2006-2007, Ext JS, LLC.
10877 * Originally Released Under LGPL - original licence link has changed is not relivant.
10880 * <script type="text/javascript">
10884 * @class Roo.CompositeElementLite
10885 * @extends Roo.CompositeElement
10886 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10888 var els = Roo.select("#some-el div.some-class");
10889 // or select directly from an existing element
10890 var el = Roo.get('some-el');
10891 el.select('div.some-class');
10893 els.setWidth(100); // all elements become 100 width
10894 els.hide(true); // all elements fade out and hide
10896 els.setWidth(100).hide(true);
10897 </code></pre><br><br>
10898 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10899 * actions will be performed on all the elements in this collection.</b>
10901 Roo.CompositeElementLite = function(els){
10902 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10903 this.el = new Roo.Element.Flyweight();
10905 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10906 addElements : function(els){
10908 if(els instanceof Array){
10909 this.elements = this.elements.concat(els);
10911 var yels = this.elements;
10912 var index = yels.length-1;
10913 for(var i = 0, len = els.length; i < len; i++) {
10914 yels[++index] = els[i];
10920 invoke : function(fn, args){
10921 var els = this.elements;
10923 for(var i = 0, len = els.length; i < len; i++) {
10925 Roo.Element.prototype[fn].apply(el, args);
10930 * Returns a flyweight Element of the dom element object at the specified index
10931 * @param {Number} index
10932 * @return {Roo.Element}
10934 item : function(index){
10935 if(!this.elements[index]){
10938 this.el.dom = this.elements[index];
10942 // fixes scope with flyweight
10943 addListener : function(eventName, handler, scope, opt){
10944 var els = this.elements;
10945 for(var i = 0, len = els.length; i < len; i++) {
10946 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10952 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10953 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10954 * a reference to the dom node, use el.dom.</b>
10955 * @param {Function} fn The function to call
10956 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10957 * @return {CompositeElement} this
10959 each : function(fn, scope){
10960 var els = this.elements;
10962 for(var i = 0, len = els.length; i < len; i++){
10964 if(fn.call(scope || el, el, this, i) === false){
10971 indexOf : function(el){
10972 return this.elements.indexOf(Roo.getDom(el));
10975 replaceElement : function(el, replacement, domReplace){
10976 var index = typeof el == 'number' ? el : this.indexOf(el);
10978 replacement = Roo.getDom(replacement);
10980 var d = this.elements[index];
10981 d.parentNode.insertBefore(replacement, d);
10982 d.parentNode.removeChild(d);
10984 this.elements.splice(index, 1, replacement);
10989 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10993 * Ext JS Library 1.1.1
10994 * Copyright(c) 2006-2007, Ext JS, LLC.
10996 * Originally Released Under LGPL - original licence link has changed is not relivant.
10999 * <script type="text/javascript">
11005 * @class Roo.data.Connection
11006 * @extends Roo.util.Observable
11007 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11008 * either to a configured URL, or to a URL specified at request time.<br><br>
11010 * Requests made by this class are asynchronous, and will return immediately. No data from
11011 * the server will be available to the statement immediately following the {@link #request} call.
11012 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11014 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11015 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11016 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11017 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11018 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11019 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11020 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11021 * standard DOM methods.
11023 * @param {Object} config a configuration object.
11025 Roo.data.Connection = function(config){
11026 Roo.apply(this, config);
11029 * @event beforerequest
11030 * Fires before a network request is made to retrieve a data object.
11031 * @param {Connection} conn This Connection object.
11032 * @param {Object} options The options config object passed to the {@link #request} method.
11034 "beforerequest" : true,
11036 * @event requestcomplete
11037 * Fires if the request was successfully completed.
11038 * @param {Connection} conn This Connection object.
11039 * @param {Object} response The XHR object containing the response data.
11040 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11041 * @param {Object} options The options config object passed to the {@link #request} method.
11043 "requestcomplete" : true,
11045 * @event requestexception
11046 * Fires if an error HTTP status was returned from the server.
11047 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11048 * @param {Connection} conn This Connection object.
11049 * @param {Object} response The XHR object containing the response data.
11050 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11051 * @param {Object} options The options config object passed to the {@link #request} method.
11053 "requestexception" : true
11055 Roo.data.Connection.superclass.constructor.call(this);
11058 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11060 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11063 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11064 * extra parameters to each request made by this object. (defaults to undefined)
11067 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11068 * to each request made by this object. (defaults to undefined)
11071 * @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)
11074 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11078 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11084 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11087 disableCaching: true,
11090 * Sends an HTTP request to a remote server.
11091 * @param {Object} options An object which may contain the following properties:<ul>
11092 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11093 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11094 * request, a url encoded string or a function to call to get either.</li>
11095 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11096 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11097 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11098 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11099 * <li>options {Object} The parameter to the request call.</li>
11100 * <li>success {Boolean} True if the request succeeded.</li>
11101 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11103 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11104 * The callback is passed the following parameters:<ul>
11105 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11106 * <li>options {Object} The parameter to the request call.</li>
11108 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11109 * The callback is passed the following parameters:<ul>
11110 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11111 * <li>options {Object} The parameter to the request call.</li>
11113 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11114 * for the callback function. Defaults to the browser window.</li>
11115 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11116 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11117 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11118 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11119 * params for the post data. Any params will be appended to the URL.</li>
11120 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11122 * @return {Number} transactionId
11124 request : function(o){
11125 if(this.fireEvent("beforerequest", this, o) !== false){
11128 if(typeof p == "function"){
11129 p = p.call(o.scope||window, o);
11131 if(typeof p == "object"){
11132 p = Roo.urlEncode(o.params);
11134 if(this.extraParams){
11135 var extras = Roo.urlEncode(this.extraParams);
11136 p = p ? (p + '&' + extras) : extras;
11139 var url = o.url || this.url;
11140 if(typeof url == 'function'){
11141 url = url.call(o.scope||window, o);
11145 var form = Roo.getDom(o.form);
11146 url = url || form.action;
11148 var enctype = form.getAttribute("enctype");
11149 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11150 return this.doFormUpload(o, p, url);
11152 var f = Roo.lib.Ajax.serializeForm(form);
11153 p = p ? (p + '&' + f) : f;
11156 var hs = o.headers;
11157 if(this.defaultHeaders){
11158 hs = Roo.apply(hs || {}, this.defaultHeaders);
11165 success: this.handleResponse,
11166 failure: this.handleFailure,
11168 argument: {options: o},
11169 timeout : this.timeout
11172 var method = o.method||this.method||(p ? "POST" : "GET");
11174 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11175 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11178 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11182 }else if(this.autoAbort !== false){
11186 if((method == 'GET' && p) || o.xmlData){
11187 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11190 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11191 return this.transId;
11193 Roo.callback(o.callback, o.scope, [o, null, null]);
11199 * Determine whether this object has a request outstanding.
11200 * @param {Number} transactionId (Optional) defaults to the last transaction
11201 * @return {Boolean} True if there is an outstanding request.
11203 isLoading : function(transId){
11205 return Roo.lib.Ajax.isCallInProgress(transId);
11207 return this.transId ? true : false;
11212 * Aborts any outstanding request.
11213 * @param {Number} transactionId (Optional) defaults to the last transaction
11215 abort : function(transId){
11216 if(transId || this.isLoading()){
11217 Roo.lib.Ajax.abort(transId || this.transId);
11222 handleResponse : function(response){
11223 this.transId = false;
11224 var options = response.argument.options;
11225 response.argument = options ? options.argument : null;
11226 this.fireEvent("requestcomplete", this, response, options);
11227 Roo.callback(options.success, options.scope, [response, options]);
11228 Roo.callback(options.callback, options.scope, [options, true, response]);
11232 handleFailure : function(response, e){
11233 this.transId = false;
11234 var options = response.argument.options;
11235 response.argument = options ? options.argument : null;
11236 this.fireEvent("requestexception", this, response, options, e);
11237 Roo.callback(options.failure, options.scope, [response, options]);
11238 Roo.callback(options.callback, options.scope, [options, false, response]);
11242 doFormUpload : function(o, ps, url){
11244 var frame = document.createElement('iframe');
11247 frame.className = 'x-hidden';
11249 frame.src = Roo.SSL_SECURE_URL;
11251 document.body.appendChild(frame);
11254 document.frames[id].name = id;
11257 var form = Roo.getDom(o.form);
11259 form.method = 'POST';
11260 form.enctype = form.encoding = 'multipart/form-data';
11266 if(ps){ // add dynamic params
11268 ps = Roo.urlDecode(ps, false);
11270 if(ps.hasOwnProperty(k)){
11271 hd = document.createElement('input');
11272 hd.type = 'hidden';
11275 form.appendChild(hd);
11282 var r = { // bogus response object
11287 r.argument = o ? o.argument : null;
11292 doc = frame.contentWindow.document;
11294 doc = (frame.contentDocument || window.frames[id].document);
11296 if(doc && doc.body){
11297 r.responseText = doc.body.innerHTML;
11299 if(doc && doc.XMLDocument){
11300 r.responseXML = doc.XMLDocument;
11302 r.responseXML = doc;
11309 Roo.EventManager.removeListener(frame, 'load', cb, this);
11311 this.fireEvent("requestcomplete", this, r, o);
11312 Roo.callback(o.success, o.scope, [r, o]);
11313 Roo.callback(o.callback, o.scope, [o, true, r]);
11315 setTimeout(function(){document.body.removeChild(frame);}, 100);
11318 Roo.EventManager.on(frame, 'load', cb, this);
11321 if(hiddens){ // remove dynamic params
11322 for(var i = 0, len = hiddens.length; i < len; i++){
11323 form.removeChild(hiddens[i]);
11331 * @extends Roo.data.Connection
11332 * Global Ajax request class.
11336 Roo.Ajax = new Roo.data.Connection({
11339 * @cfg {String} url @hide
11342 * @cfg {Object} extraParams @hide
11345 * @cfg {Object} defaultHeaders @hide
11348 * @cfg {String} method (Optional) @hide
11351 * @cfg {Number} timeout (Optional) @hide
11354 * @cfg {Boolean} autoAbort (Optional) @hide
11358 * @cfg {Boolean} disableCaching (Optional) @hide
11362 * @property disableCaching
11363 * True to add a unique cache-buster param to GET requests. (defaults to true)
11368 * The default URL to be used for requests to the server. (defaults to undefined)
11372 * @property extraParams
11373 * An object containing properties which are used as
11374 * extra parameters to each request made by this object. (defaults to undefined)
11378 * @property defaultHeaders
11379 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11384 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11388 * @property timeout
11389 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11394 * @property autoAbort
11395 * Whether a new request should abort any pending requests. (defaults to false)
11401 * Serialize the passed form into a url encoded string
11402 * @param {String/HTMLElement} form
11405 serializeForm : function(form){
11406 return Roo.lib.Ajax.serializeForm(form);
11410 * Ext JS Library 1.1.1
11411 * Copyright(c) 2006-2007, Ext JS, LLC.
11413 * Originally Released Under LGPL - original licence link has changed is not relivant.
11416 * <script type="text/javascript">
11421 * @extends Roo.data.Connection
11422 * Global Ajax request class.
11424 * @instanceOf Roo.data.Connection
11426 Roo.Ajax = new Roo.data.Connection({
11435 * @cfg {String} url @hide
11438 * @cfg {Object} extraParams @hide
11441 * @cfg {Object} defaultHeaders @hide
11444 * @cfg {String} method (Optional) @hide
11447 * @cfg {Number} timeout (Optional) @hide
11450 * @cfg {Boolean} autoAbort (Optional) @hide
11454 * @cfg {Boolean} disableCaching (Optional) @hide
11458 * @property disableCaching
11459 * True to add a unique cache-buster param to GET requests. (defaults to true)
11464 * The default URL to be used for requests to the server. (defaults to undefined)
11468 * @property extraParams
11469 * An object containing properties which are used as
11470 * extra parameters to each request made by this object. (defaults to undefined)
11474 * @property defaultHeaders
11475 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11480 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11484 * @property timeout
11485 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11490 * @property autoAbort
11491 * Whether a new request should abort any pending requests. (defaults to false)
11497 * Serialize the passed form into a url encoded string
11498 * @param {String/HTMLElement} form
11501 serializeForm : function(form){
11502 return Roo.lib.Ajax.serializeForm(form);
11506 * Ext JS Library 1.1.1
11507 * Copyright(c) 2006-2007, Ext JS, LLC.
11509 * Originally Released Under LGPL - original licence link has changed is not relivant.
11512 * <script type="text/javascript">
11517 * @class Roo.UpdateManager
11518 * @extends Roo.util.Observable
11519 * Provides AJAX-style update for Element object.<br><br>
11522 * // Get it from a Roo.Element object
11523 * var el = Roo.get("foo");
11524 * var mgr = el.getUpdateManager();
11525 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11527 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11529 * // or directly (returns the same UpdateManager instance)
11530 * var mgr = new Roo.UpdateManager("myElementId");
11531 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11532 * mgr.on("update", myFcnNeedsToKnow);
11534 // short handed call directly from the element object
11535 Roo.get("foo").load({
11539 text: "Loading Foo..."
11543 * Create new UpdateManager directly.
11544 * @param {String/HTMLElement/Roo.Element} el The element to update
11545 * @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).
11547 Roo.UpdateManager = function(el, forceNew){
11549 if(!forceNew && el.updateManager){
11550 return el.updateManager;
11553 * The Element object
11554 * @type Roo.Element
11558 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11561 this.defaultUrl = null;
11565 * @event beforeupdate
11566 * Fired before an update is made, return false from your handler and the update is cancelled.
11567 * @param {Roo.Element} el
11568 * @param {String/Object/Function} url
11569 * @param {String/Object} params
11571 "beforeupdate": true,
11574 * Fired after successful update is made.
11575 * @param {Roo.Element} el
11576 * @param {Object} oResponseObject The response Object
11581 * Fired on update failure.
11582 * @param {Roo.Element} el
11583 * @param {Object} oResponseObject The response Object
11587 var d = Roo.UpdateManager.defaults;
11589 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11592 this.sslBlankUrl = d.sslBlankUrl;
11594 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11597 this.disableCaching = d.disableCaching;
11599 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11602 this.indicatorText = d.indicatorText;
11604 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11607 this.showLoadIndicator = d.showLoadIndicator;
11609 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11612 this.timeout = d.timeout;
11615 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11618 this.loadScripts = d.loadScripts;
11621 * Transaction object of current executing transaction
11623 this.transaction = null;
11628 this.autoRefreshProcId = null;
11630 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11633 this.refreshDelegate = this.refresh.createDelegate(this);
11635 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11638 this.updateDelegate = this.update.createDelegate(this);
11640 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11643 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11647 this.successDelegate = this.processSuccess.createDelegate(this);
11651 this.failureDelegate = this.processFailure.createDelegate(this);
11653 if(!this.renderer){
11655 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11657 this.renderer = new Roo.UpdateManager.BasicRenderer();
11660 Roo.UpdateManager.superclass.constructor.call(this);
11663 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11665 * Get the Element this UpdateManager is bound to
11666 * @return {Roo.Element} The element
11668 getEl : function(){
11672 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11673 * @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:
11676 url: "your-url.php",<br/>
11677 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11678 callback: yourFunction,<br/>
11679 scope: yourObject, //(optional scope) <br/>
11680 discardUrl: false, <br/>
11681 nocache: false,<br/>
11682 text: "Loading...",<br/>
11684 scripts: false<br/>
11687 * The only required property is url. The optional properties nocache, text and scripts
11688 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11689 * @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}
11690 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11691 * @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.
11693 update : function(url, params, callback, discardUrl){
11694 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11695 var method = this.method, cfg;
11696 if(typeof url == "object"){ // must be config object
11699 params = params || cfg.params;
11700 callback = callback || cfg.callback;
11701 discardUrl = discardUrl || cfg.discardUrl;
11702 if(callback && cfg.scope){
11703 callback = callback.createDelegate(cfg.scope);
11705 if(typeof cfg.method != "undefined"){method = cfg.method;};
11706 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11707 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11708 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11709 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11711 this.showLoading();
11713 this.defaultUrl = url;
11715 if(typeof url == "function"){
11716 url = url.call(this);
11719 method = method || (params ? "POST" : "GET");
11720 if(method == "GET"){
11721 url = this.prepareUrl(url);
11724 var o = Roo.apply(cfg ||{}, {
11727 success: this.successDelegate,
11728 failure: this.failureDelegate,
11729 callback: undefined,
11730 timeout: (this.timeout*1000),
11731 argument: {"url": url, "form": null, "callback": callback, "params": params}
11734 this.transaction = Roo.Ajax.request(o);
11739 * 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.
11740 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11741 * @param {String/HTMLElement} form The form Id or form element
11742 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11743 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11744 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11746 formUpdate : function(form, url, reset, callback){
11747 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11748 if(typeof url == "function"){
11749 url = url.call(this);
11751 form = Roo.getDom(form);
11752 this.transaction = Roo.Ajax.request({
11755 success: this.successDelegate,
11756 failure: this.failureDelegate,
11757 timeout: (this.timeout*1000),
11758 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11760 this.showLoading.defer(1, this);
11765 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11766 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11768 refresh : function(callback){
11769 if(this.defaultUrl == null){
11772 this.update(this.defaultUrl, null, callback, true);
11776 * Set this element to auto refresh.
11777 * @param {Number} interval How often to update (in seconds).
11778 * @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)
11779 * @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}
11780 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11781 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11783 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11785 this.update(url || this.defaultUrl, params, callback, true);
11787 if(this.autoRefreshProcId){
11788 clearInterval(this.autoRefreshProcId);
11790 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11794 * Stop auto refresh on this element.
11796 stopAutoRefresh : function(){
11797 if(this.autoRefreshProcId){
11798 clearInterval(this.autoRefreshProcId);
11799 delete this.autoRefreshProcId;
11803 isAutoRefreshing : function(){
11804 return this.autoRefreshProcId ? true : false;
11807 * Called to update the element to "Loading" state. Override to perform custom action.
11809 showLoading : function(){
11810 if(this.showLoadIndicator){
11811 this.el.update(this.indicatorText);
11816 * Adds unique parameter to query string if disableCaching = true
11819 prepareUrl : function(url){
11820 if(this.disableCaching){
11821 var append = "_dc=" + (new Date().getTime());
11822 if(url.indexOf("?") !== -1){
11823 url += "&" + append;
11825 url += "?" + append;
11834 processSuccess : function(response){
11835 this.transaction = null;
11836 if(response.argument.form && response.argument.reset){
11837 try{ // put in try/catch since some older FF releases had problems with this
11838 response.argument.form.reset();
11841 if(this.loadScripts){
11842 this.renderer.render(this.el, response, this,
11843 this.updateComplete.createDelegate(this, [response]));
11845 this.renderer.render(this.el, response, this);
11846 this.updateComplete(response);
11850 updateComplete : function(response){
11851 this.fireEvent("update", this.el, response);
11852 if(typeof response.argument.callback == "function"){
11853 response.argument.callback(this.el, true, response);
11860 processFailure : function(response){
11861 this.transaction = null;
11862 this.fireEvent("failure", this.el, response);
11863 if(typeof response.argument.callback == "function"){
11864 response.argument.callback(this.el, false, response);
11869 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11870 * @param {Object} renderer The object implementing the render() method
11872 setRenderer : function(renderer){
11873 this.renderer = renderer;
11876 getRenderer : function(){
11877 return this.renderer;
11881 * Set the defaultUrl used for updates
11882 * @param {String/Function} defaultUrl The url or a function to call to get the url
11884 setDefaultUrl : function(defaultUrl){
11885 this.defaultUrl = defaultUrl;
11889 * Aborts the executing transaction
11891 abort : function(){
11892 if(this.transaction){
11893 Roo.Ajax.abort(this.transaction);
11898 * Returns true if an update is in progress
11899 * @return {Boolean}
11901 isUpdating : function(){
11902 if(this.transaction){
11903 return Roo.Ajax.isLoading(this.transaction);
11910 * @class Roo.UpdateManager.defaults
11911 * @static (not really - but it helps the doc tool)
11912 * The defaults collection enables customizing the default properties of UpdateManager
11914 Roo.UpdateManager.defaults = {
11916 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11922 * True to process scripts by default (Defaults to false).
11925 loadScripts : false,
11928 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11931 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11933 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11936 disableCaching : false,
11938 * Whether to show indicatorText when loading (Defaults to true).
11941 showLoadIndicator : true,
11943 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11946 indicatorText : '<div class="loading-indicator">Loading...</div>'
11950 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11952 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11953 * @param {String/HTMLElement/Roo.Element} el The element to update
11954 * @param {String} url The url
11955 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11956 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11959 * @member Roo.UpdateManager
11961 Roo.UpdateManager.updateElement = function(el, url, params, options){
11962 var um = Roo.get(el, true).getUpdateManager();
11963 Roo.apply(um, options);
11964 um.update(url, params, options ? options.callback : null);
11966 // alias for backwards compat
11967 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11969 * @class Roo.UpdateManager.BasicRenderer
11970 * Default Content renderer. Updates the elements innerHTML with the responseText.
11972 Roo.UpdateManager.BasicRenderer = function(){};
11974 Roo.UpdateManager.BasicRenderer.prototype = {
11976 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11977 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11978 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11979 * @param {Roo.Element} el The element being rendered
11980 * @param {Object} response The YUI Connect response object
11981 * @param {UpdateManager} updateManager The calling update manager
11982 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11984 render : function(el, response, updateManager, callback){
11985 el.update(response.responseText, updateManager.loadScripts, callback);
11990 * Ext JS Library 1.1.1
11991 * Copyright(c) 2006-2007, Ext JS, LLC.
11993 * Originally Released Under LGPL - original licence link has changed is not relivant.
11996 * <script type="text/javascript">
12000 * @class Roo.util.DelayedTask
12001 * Provides a convenient method of performing setTimeout where a new
12002 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12003 * You can use this class to buffer
12004 * the keypress events for a certain number of milliseconds, and perform only if they stop
12005 * for that amount of time.
12006 * @constructor The parameters to this constructor serve as defaults and are not required.
12007 * @param {Function} fn (optional) The default function to timeout
12008 * @param {Object} scope (optional) The default scope of that timeout
12009 * @param {Array} args (optional) The default Array of arguments
12011 Roo.util.DelayedTask = function(fn, scope, args){
12012 var id = null, d, t;
12014 var call = function(){
12015 var now = new Date().getTime();
12019 fn.apply(scope, args || []);
12023 * Cancels any pending timeout and queues a new one
12024 * @param {Number} delay The milliseconds to delay
12025 * @param {Function} newFn (optional) Overrides function passed to constructor
12026 * @param {Object} newScope (optional) Overrides scope passed to constructor
12027 * @param {Array} newArgs (optional) Overrides args passed to constructor
12029 this.delay = function(delay, newFn, newScope, newArgs){
12030 if(id && delay != d){
12034 t = new Date().getTime();
12036 scope = newScope || scope;
12037 args = newArgs || args;
12039 id = setInterval(call, d);
12044 * Cancel the last queued timeout
12046 this.cancel = function(){
12054 * Ext JS Library 1.1.1
12055 * Copyright(c) 2006-2007, Ext JS, LLC.
12057 * Originally Released Under LGPL - original licence link has changed is not relivant.
12060 * <script type="text/javascript">
12064 Roo.util.TaskRunner = function(interval){
12065 interval = interval || 10;
12066 var tasks = [], removeQueue = [];
12068 var running = false;
12070 var stopThread = function(){
12076 var startThread = function(){
12079 id = setInterval(runTasks, interval);
12083 var removeTask = function(task){
12084 removeQueue.push(task);
12090 var runTasks = function(){
12091 if(removeQueue.length > 0){
12092 for(var i = 0, len = removeQueue.length; i < len; i++){
12093 tasks.remove(removeQueue[i]);
12096 if(tasks.length < 1){
12101 var now = new Date().getTime();
12102 for(var i = 0, len = tasks.length; i < len; ++i){
12104 var itime = now - t.taskRunTime;
12105 if(t.interval <= itime){
12106 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12107 t.taskRunTime = now;
12108 if(rt === false || t.taskRunCount === t.repeat){
12113 if(t.duration && t.duration <= (now - t.taskStartTime)){
12120 * Queues a new task.
12121 * @param {Object} task
12123 this.start = function(task){
12125 task.taskStartTime = new Date().getTime();
12126 task.taskRunTime = 0;
12127 task.taskRunCount = 0;
12132 this.stop = function(task){
12137 this.stopAll = function(){
12139 for(var i = 0, len = tasks.length; i < len; i++){
12140 if(tasks[i].onStop){
12149 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12151 * Ext JS Library 1.1.1
12152 * Copyright(c) 2006-2007, Ext JS, LLC.
12154 * Originally Released Under LGPL - original licence link has changed is not relivant.
12157 * <script type="text/javascript">
12162 * @class Roo.util.MixedCollection
12163 * @extends Roo.util.Observable
12164 * A Collection class that maintains both numeric indexes and keys and exposes events.
12166 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12167 * collection (defaults to false)
12168 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12169 * and return the key value for that item. This is used when available to look up the key on items that
12170 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12171 * equivalent to providing an implementation for the {@link #getKey} method.
12173 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12181 * Fires when the collection is cleared.
12186 * Fires when an item is added to the collection.
12187 * @param {Number} index The index at which the item was added.
12188 * @param {Object} o The item added.
12189 * @param {String} key The key associated with the added item.
12194 * Fires when an item is replaced in the collection.
12195 * @param {String} key he key associated with the new added.
12196 * @param {Object} old The item being replaced.
12197 * @param {Object} new The new item.
12202 * Fires when an item is removed from the collection.
12203 * @param {Object} o The item being removed.
12204 * @param {String} key (optional) The key associated with the removed item.
12209 this.allowFunctions = allowFunctions === true;
12211 this.getKey = keyFn;
12213 Roo.util.MixedCollection.superclass.constructor.call(this);
12216 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12217 allowFunctions : false,
12220 * Adds an item to the collection.
12221 * @param {String} key The key to associate with the item
12222 * @param {Object} o The item to add.
12223 * @return {Object} The item added.
12225 add : function(key, o){
12226 if(arguments.length == 1){
12228 key = this.getKey(o);
12230 if(typeof key == "undefined" || key === null){
12232 this.items.push(o);
12233 this.keys.push(null);
12235 var old = this.map[key];
12237 return this.replace(key, o);
12240 this.items.push(o);
12242 this.keys.push(key);
12244 this.fireEvent("add", this.length-1, o, key);
12249 * MixedCollection has a generic way to fetch keys if you implement getKey.
12252 var mc = new Roo.util.MixedCollection();
12253 mc.add(someEl.dom.id, someEl);
12254 mc.add(otherEl.dom.id, otherEl);
12258 var mc = new Roo.util.MixedCollection();
12259 mc.getKey = function(el){
12265 // or via the constructor
12266 var mc = new Roo.util.MixedCollection(false, function(el){
12272 * @param o {Object} The item for which to find the key.
12273 * @return {Object} The key for the passed item.
12275 getKey : function(o){
12280 * Replaces an item in the collection.
12281 * @param {String} key The key associated with the item to replace, or the item to replace.
12282 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12283 * @return {Object} The new item.
12285 replace : function(key, o){
12286 if(arguments.length == 1){
12288 key = this.getKey(o);
12290 var old = this.item(key);
12291 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12292 return this.add(key, o);
12294 var index = this.indexOfKey(key);
12295 this.items[index] = o;
12297 this.fireEvent("replace", key, old, o);
12302 * Adds all elements of an Array or an Object to the collection.
12303 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12304 * an Array of values, each of which are added to the collection.
12306 addAll : function(objs){
12307 if(arguments.length > 1 || objs instanceof Array){
12308 var args = arguments.length > 1 ? arguments : objs;
12309 for(var i = 0, len = args.length; i < len; i++){
12313 for(var key in objs){
12314 if(this.allowFunctions || typeof objs[key] != "function"){
12315 this.add(key, objs[key]);
12322 * Executes the specified function once for every item in the collection, passing each
12323 * item as the first and only parameter. returning false from the function will stop the iteration.
12324 * @param {Function} fn The function to execute for each item.
12325 * @param {Object} scope (optional) The scope in which to execute the function.
12327 each : function(fn, scope){
12328 var items = [].concat(this.items); // each safe for removal
12329 for(var i = 0, len = items.length; i < len; i++){
12330 if(fn.call(scope || items[i], items[i], i, len) === false){
12337 * Executes the specified function once for every key in the collection, passing each
12338 * key, and its associated item as the first two parameters.
12339 * @param {Function} fn The function to execute for each item.
12340 * @param {Object} scope (optional) The scope in which to execute the function.
12342 eachKey : function(fn, scope){
12343 for(var i = 0, len = this.keys.length; i < len; i++){
12344 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12349 * Returns the first item in the collection which elicits a true return value from the
12350 * passed selection function.
12351 * @param {Function} fn The selection function to execute for each item.
12352 * @param {Object} scope (optional) The scope in which to execute the function.
12353 * @return {Object} The first item in the collection which returned true from the selection function.
12355 find : function(fn, scope){
12356 for(var i = 0, len = this.items.length; i < len; i++){
12357 if(fn.call(scope || window, this.items[i], this.keys[i])){
12358 return this.items[i];
12365 * Inserts an item at the specified index in the collection.
12366 * @param {Number} index The index to insert the item at.
12367 * @param {String} key The key to associate with the new item, or the item itself.
12368 * @param {Object} o (optional) If the second parameter was a key, the new item.
12369 * @return {Object} The item inserted.
12371 insert : function(index, key, o){
12372 if(arguments.length == 2){
12374 key = this.getKey(o);
12376 if(index >= this.length){
12377 return this.add(key, o);
12380 this.items.splice(index, 0, o);
12381 if(typeof key != "undefined" && key != null){
12384 this.keys.splice(index, 0, key);
12385 this.fireEvent("add", index, o, key);
12390 * Removed an item from the collection.
12391 * @param {Object} o The item to remove.
12392 * @return {Object} The item removed.
12394 remove : function(o){
12395 return this.removeAt(this.indexOf(o));
12399 * Remove an item from a specified index in the collection.
12400 * @param {Number} index The index within the collection of the item to remove.
12402 removeAt : function(index){
12403 if(index < this.length && index >= 0){
12405 var o = this.items[index];
12406 this.items.splice(index, 1);
12407 var key = this.keys[index];
12408 if(typeof key != "undefined"){
12409 delete this.map[key];
12411 this.keys.splice(index, 1);
12412 this.fireEvent("remove", o, key);
12417 * Removed an item associated with the passed key fom the collection.
12418 * @param {String} key The key of the item to remove.
12420 removeKey : function(key){
12421 return this.removeAt(this.indexOfKey(key));
12425 * Returns the number of items in the collection.
12426 * @return {Number} the number of items in the collection.
12428 getCount : function(){
12429 return this.length;
12433 * Returns index within the collection of the passed Object.
12434 * @param {Object} o The item to find the index of.
12435 * @return {Number} index of the item.
12437 indexOf : function(o){
12438 if(!this.items.indexOf){
12439 for(var i = 0, len = this.items.length; i < len; i++){
12440 if(this.items[i] == o) return i;
12444 return this.items.indexOf(o);
12449 * Returns index within the collection of the passed key.
12450 * @param {String} key The key to find the index of.
12451 * @return {Number} index of the key.
12453 indexOfKey : function(key){
12454 if(!this.keys.indexOf){
12455 for(var i = 0, len = this.keys.length; i < len; i++){
12456 if(this.keys[i] == key) return i;
12460 return this.keys.indexOf(key);
12465 * Returns the item associated with the passed key OR index. Key has priority over index.
12466 * @param {String/Number} key The key or index of the item.
12467 * @return {Object} The item associated with the passed key.
12469 item : function(key){
12470 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12471 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12475 * Returns the item at the specified index.
12476 * @param {Number} index The index of the item.
12479 itemAt : function(index){
12480 return this.items[index];
12484 * Returns the item associated with the passed key.
12485 * @param {String/Number} key The key of the item.
12486 * @return {Object} The item associated with the passed key.
12488 key : function(key){
12489 return this.map[key];
12493 * Returns true if the collection contains the passed Object as an item.
12494 * @param {Object} o The Object to look for in the collection.
12495 * @return {Boolean} True if the collection contains the Object as an item.
12497 contains : function(o){
12498 return this.indexOf(o) != -1;
12502 * Returns true if the collection contains the passed Object as a key.
12503 * @param {String} key The key to look for in the collection.
12504 * @return {Boolean} True if the collection contains the Object as a key.
12506 containsKey : function(key){
12507 return typeof this.map[key] != "undefined";
12511 * Removes all items from the collection.
12513 clear : function(){
12518 this.fireEvent("clear");
12522 * Returns the first item in the collection.
12523 * @return {Object} the first item in the collection..
12525 first : function(){
12526 return this.items[0];
12530 * Returns the last item in the collection.
12531 * @return {Object} the last item in the collection..
12534 return this.items[this.length-1];
12537 _sort : function(property, dir, fn){
12538 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12539 fn = fn || function(a, b){
12542 var c = [], k = this.keys, items = this.items;
12543 for(var i = 0, len = items.length; i < len; i++){
12544 c[c.length] = {key: k[i], value: items[i], index: i};
12546 c.sort(function(a, b){
12547 var v = fn(a[property], b[property]) * dsc;
12549 v = (a.index < b.index ? -1 : 1);
12553 for(var i = 0, len = c.length; i < len; i++){
12554 items[i] = c[i].value;
12557 this.fireEvent("sort", this);
12561 * Sorts this collection with the passed comparison function
12562 * @param {String} direction (optional) "ASC" or "DESC"
12563 * @param {Function} fn (optional) comparison function
12565 sort : function(dir, fn){
12566 this._sort("value", dir, fn);
12570 * Sorts this collection by keys
12571 * @param {String} direction (optional) "ASC" or "DESC"
12572 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12574 keySort : function(dir, fn){
12575 this._sort("key", dir, fn || function(a, b){
12576 return String(a).toUpperCase()-String(b).toUpperCase();
12581 * Returns a range of items in this collection
12582 * @param {Number} startIndex (optional) defaults to 0
12583 * @param {Number} endIndex (optional) default to the last item
12584 * @return {Array} An array of items
12586 getRange : function(start, end){
12587 var items = this.items;
12588 if(items.length < 1){
12591 start = start || 0;
12592 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12595 for(var i = start; i <= end; i++) {
12596 r[r.length] = items[i];
12599 for(var i = start; i >= end; i--) {
12600 r[r.length] = items[i];
12607 * Filter the <i>objects</i> in this collection by a specific property.
12608 * Returns a new collection that has been filtered.
12609 * @param {String} property A property on your objects
12610 * @param {String/RegExp} value Either string that the property values
12611 * should start with or a RegExp to test against the property
12612 * @return {MixedCollection} The new filtered collection
12614 filter : function(property, value){
12615 if(!value.exec){ // not a regex
12616 value = String(value);
12617 if(value.length == 0){
12618 return this.clone();
12620 value = new RegExp("^" + Roo.escapeRe(value), "i");
12622 return this.filterBy(function(o){
12623 return o && value.test(o[property]);
12628 * Filter by a function. * Returns a new collection that has been filtered.
12629 * The passed function will be called with each
12630 * object in the collection. If the function returns true, the value is included
12631 * otherwise it is filtered.
12632 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12633 * @param {Object} scope (optional) The scope of the function (defaults to this)
12634 * @return {MixedCollection} The new filtered collection
12636 filterBy : function(fn, scope){
12637 var r = new Roo.util.MixedCollection();
12638 r.getKey = this.getKey;
12639 var k = this.keys, it = this.items;
12640 for(var i = 0, len = it.length; i < len; i++){
12641 if(fn.call(scope||this, it[i], k[i])){
12642 r.add(k[i], it[i]);
12649 * Creates a duplicate of this collection
12650 * @return {MixedCollection}
12652 clone : function(){
12653 var r = new Roo.util.MixedCollection();
12654 var k = this.keys, it = this.items;
12655 for(var i = 0, len = it.length; i < len; i++){
12656 r.add(k[i], it[i]);
12658 r.getKey = this.getKey;
12663 * Returns the item associated with the passed key or index.
12665 * @param {String/Number} key The key or index of the item.
12666 * @return {Object} The item associated with the passed key.
12668 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12670 * Ext JS Library 1.1.1
12671 * Copyright(c) 2006-2007, Ext JS, LLC.
12673 * Originally Released Under LGPL - original licence link has changed is not relivant.
12676 * <script type="text/javascript">
12679 * @class Roo.util.JSON
12680 * Modified version of Douglas Crockford"s json.js that doesn"t
12681 * mess with the Object prototype
12682 * http://www.json.org/js.html
12685 Roo.util.JSON = new (function(){
12686 var useHasOwn = {}.hasOwnProperty ? true : false;
12688 // crashes Safari in some instances
12689 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12691 var pad = function(n) {
12692 return n < 10 ? "0" + n : n;
12705 var encodeString = function(s){
12706 if (/["\\\x00-\x1f]/.test(s)) {
12707 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12712 c = b.charCodeAt();
12714 Math.floor(c / 16).toString(16) +
12715 (c % 16).toString(16);
12718 return '"' + s + '"';
12721 var encodeArray = function(o){
12722 var a = ["["], b, i, l = o.length, v;
12723 for (i = 0; i < l; i += 1) {
12725 switch (typeof v) {
12734 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12742 var encodeDate = function(o){
12743 return '"' + o.getFullYear() + "-" +
12744 pad(o.getMonth() + 1) + "-" +
12745 pad(o.getDate()) + "T" +
12746 pad(o.getHours()) + ":" +
12747 pad(o.getMinutes()) + ":" +
12748 pad(o.getSeconds()) + '"';
12752 * Encodes an Object, Array or other value
12753 * @param {Mixed} o The variable to encode
12754 * @return {String} The JSON string
12756 this.encode = function(o){
12757 if(typeof o == "undefined" || o === null){
12759 }else if(o instanceof Array){
12760 return encodeArray(o);
12761 }else if(o instanceof Date){
12762 return encodeDate(o);
12763 }else if(typeof o == "string"){
12764 return encodeString(o);
12765 }else if(typeof o == "number"){
12766 return isFinite(o) ? String(o) : "null";
12767 }else if(typeof o == "boolean"){
12770 var a = ["{"], b, i, v;
12772 if(!useHasOwn || o.hasOwnProperty(i)) {
12774 switch (typeof v) {
12783 a.push(this.encode(i), ":",
12784 v === null ? "null" : this.encode(v));
12795 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12796 * @param {String} json The JSON string
12797 * @return {Object} The resulting object
12799 this.decode = function(json){
12803 return eval("(" + json + ')');
12807 * Shorthand for {@link Roo.util.JSON#encode}
12808 * @member Roo encode
12810 Roo.encode = Roo.util.JSON.encode;
12812 * Shorthand for {@link Roo.util.JSON#decode}
12813 * @member Roo decode
12815 Roo.decode = Roo.util.JSON.decode;
12818 * Ext JS Library 1.1.1
12819 * Copyright(c) 2006-2007, Ext JS, LLC.
12821 * Originally Released Under LGPL - original licence link has changed is not relivant.
12824 * <script type="text/javascript">
12828 * @class Roo.util.Format
12829 * Reusable data formatting functions
12832 Roo.util.Format = function(){
12833 var trimRe = /^\s+|\s+$/g;
12836 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12837 * @param {String} value The string to truncate
12838 * @param {Number} length The maximum length to allow before truncating
12839 * @return {String} The converted text
12841 ellipsis : function(value, len){
12842 if(value && value.length > len){
12843 return value.substr(0, len-3)+"...";
12849 * Checks a reference and converts it to empty string if it is undefined
12850 * @param {Mixed} value Reference to check
12851 * @return {Mixed} Empty string if converted, otherwise the original value
12853 undef : function(value){
12854 return typeof value != "undefined" ? value : "";
12858 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12859 * @param {String} value The string to encode
12860 * @return {String} The encoded text
12862 htmlEncode : function(value){
12863 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12867 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12868 * @param {String} value The string to decode
12869 * @return {String} The decoded text
12871 htmlDecode : function(value){
12872 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12876 * Trims any whitespace from either side of a string
12877 * @param {String} value The text to trim
12878 * @return {String} The trimmed text
12880 trim : function(value){
12881 return String(value).replace(trimRe, "");
12885 * Returns a substring from within an original string
12886 * @param {String} value The original text
12887 * @param {Number} start The start index of the substring
12888 * @param {Number} length The length of the substring
12889 * @return {String} The substring
12891 substr : function(value, start, length){
12892 return String(value).substr(start, length);
12896 * Converts a string to all lower case letters
12897 * @param {String} value The text to convert
12898 * @return {String} The converted text
12900 lowercase : function(value){
12901 return String(value).toLowerCase();
12905 * Converts a string to all upper case letters
12906 * @param {String} value The text to convert
12907 * @return {String} The converted text
12909 uppercase : function(value){
12910 return String(value).toUpperCase();
12914 * Converts the first character only of a string to upper case
12915 * @param {String} value The text to convert
12916 * @return {String} The converted text
12918 capitalize : function(value){
12919 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12923 call : function(value, fn){
12924 if(arguments.length > 2){
12925 var args = Array.prototype.slice.call(arguments, 2);
12926 args.unshift(value);
12928 return /** eval:var:value */ eval(fn).apply(window, args);
12930 /** eval:var:value */
12931 return /** eval:var:value */ eval(fn).call(window, value);
12936 * Format a number as US currency
12937 * @param {Number/String} value The numeric value to format
12938 * @return {String} The formatted currency string
12940 usMoney : function(v){
12941 v = (Math.round((v-0)*100))/100;
12942 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12944 var ps = v.split('.');
12946 var sub = ps[1] ? '.'+ ps[1] : '.00';
12947 var r = /(\d+)(\d{3})/;
12948 while (r.test(whole)) {
12949 whole = whole.replace(r, '$1' + ',' + '$2');
12951 return "$" + whole + sub ;
12955 * Parse a value into a formatted date using the specified format pattern.
12956 * @param {Mixed} value The value to format
12957 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12958 * @return {String} The formatted date string
12960 date : function(v, format){
12964 if(!(v instanceof Date)){
12965 v = new Date(Date.parse(v));
12967 return v.dateFormat(format || "m/d/Y");
12971 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12972 * @param {String} format Any valid date format string
12973 * @return {Function} The date formatting function
12975 dateRenderer : function(format){
12976 return function(v){
12977 return Roo.util.Format.date(v, format);
12982 stripTagsRE : /<\/?[^>]+>/gi,
12985 * Strips all HTML tags
12986 * @param {Mixed} value The text from which to strip tags
12987 * @return {String} The stripped text
12989 stripTags : function(v){
12990 return !v ? v : String(v).replace(this.stripTagsRE, "");
12995 * Ext JS Library 1.1.1
12996 * Copyright(c) 2006-2007, Ext JS, LLC.
12998 * Originally Released Under LGPL - original licence link has changed is not relivant.
13001 * <script type="text/javascript">
13008 * @class Roo.MasterTemplate
13009 * @extends Roo.Template
13010 * Provides a template that can have child templates. The syntax is:
13012 var t = new Roo.MasterTemplate(
13013 '<select name="{name}">',
13014 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13017 t.add('options', {value: 'foo', text: 'bar'});
13018 // or you can add multiple child elements in one shot
13019 t.addAll('options', [
13020 {value: 'foo', text: 'bar'},
13021 {value: 'foo2', text: 'bar2'},
13022 {value: 'foo3', text: 'bar3'}
13024 // then append, applying the master template values
13025 t.append('my-form', {name: 'my-select'});
13027 * A name attribute for the child template is not required if you have only one child
13028 * template or you want to refer to them by index.
13030 Roo.MasterTemplate = function(){
13031 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13032 this.originalHtml = this.html;
13034 var m, re = this.subTemplateRe;
13037 while(m = re.exec(this.html)){
13038 var name = m[1], content = m[2];
13043 tpl : new Roo.Template(content)
13046 st[name] = st[subIndex];
13048 st[subIndex].tpl.compile();
13049 st[subIndex].tpl.call = this.call.createDelegate(this);
13052 this.subCount = subIndex;
13055 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13057 * The regular expression used to match sub templates
13061 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13064 * Applies the passed values to a child template.
13065 * @param {String/Number} name (optional) The name or index of the child template
13066 * @param {Array/Object} values The values to be applied to the template
13067 * @return {MasterTemplate} this
13069 add : function(name, values){
13070 if(arguments.length == 1){
13071 values = arguments[0];
13074 var s = this.subs[name];
13075 s.buffer[s.buffer.length] = s.tpl.apply(values);
13080 * Applies all the passed values to a child template.
13081 * @param {String/Number} name (optional) The name or index of the child template
13082 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13083 * @param {Boolean} reset (optional) True to reset the template first
13084 * @return {MasterTemplate} this
13086 fill : function(name, values, reset){
13088 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13096 for(var i = 0, len = values.length; i < len; i++){
13097 this.add(name, values[i]);
13103 * Resets the template for reuse
13104 * @return {MasterTemplate} this
13106 reset : function(){
13108 for(var i = 0; i < this.subCount; i++){
13114 applyTemplate : function(values){
13116 var replaceIndex = -1;
13117 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13118 return s[++replaceIndex].buffer.join("");
13120 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13123 apply : function(){
13124 return this.applyTemplate.apply(this, arguments);
13127 compile : function(){return this;}
13131 * Alias for fill().
13134 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13136 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13137 * var tpl = Roo.MasterTemplate.from('element-id');
13138 * @param {String/HTMLElement} el
13139 * @param {Object} config
13142 Roo.MasterTemplate.from = function(el, config){
13143 el = Roo.getDom(el);
13144 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13147 * Ext JS Library 1.1.1
13148 * Copyright(c) 2006-2007, Ext JS, LLC.
13150 * Originally Released Under LGPL - original licence link has changed is not relivant.
13153 * <script type="text/javascript">
13158 * @class Roo.util.CSS
13159 * Utility class for manipulating CSS rules
13162 Roo.util.CSS = function(){
13164 var doc = document;
13166 var camelRe = /(-[a-z])/gi;
13167 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13171 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13172 * tag and appended to the HEAD of the document.
13173 * @param {String} cssText The text containing the css rules
13174 * @param {String} id An id to add to the stylesheet for later removal
13175 * @return {StyleSheet}
13177 createStyleSheet : function(cssText, id){
13179 var head = doc.getElementsByTagName("head")[0];
13180 var rules = doc.createElement("style");
13181 rules.setAttribute("type", "text/css");
13183 rules.setAttribute("id", id);
13186 head.appendChild(rules);
13187 ss = rules.styleSheet;
13188 ss.cssText = cssText;
13191 rules.appendChild(doc.createTextNode(cssText));
13193 rules.cssText = cssText;
13195 head.appendChild(rules);
13196 ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13198 this.cacheStyleSheet(ss);
13203 * Removes a style or link tag by id
13204 * @param {String} id The id of the tag
13206 removeStyleSheet : function(id){
13207 var existing = doc.getElementById(id);
13209 existing.parentNode.removeChild(existing);
13214 * Dynamically swaps an existing stylesheet reference for a new one
13215 * @param {String} id The id of an existing link tag to remove
13216 * @param {String} url The href of the new stylesheet to include
13218 swapStyleSheet : function(id, url){
13219 this.removeStyleSheet(id);
13220 var ss = doc.createElement("link");
13221 ss.setAttribute("rel", "stylesheet");
13222 ss.setAttribute("type", "text/css");
13223 ss.setAttribute("id", id);
13224 ss.setAttribute("href", url);
13225 doc.getElementsByTagName("head")[0].appendChild(ss);
13229 * Refresh the rule cache if you have dynamically added stylesheets
13230 * @return {Object} An object (hash) of rules indexed by selector
13232 refreshCache : function(){
13233 return this.getRules(true);
13237 cacheStyleSheet : function(ss){
13241 try{// try catch for cross domain access issue
13242 var ssRules = ss.cssRules || ss.rules;
13243 for(var j = ssRules.length-1; j >= 0; --j){
13244 rules[ssRules[j].selectorText] = ssRules[j];
13250 * Gets all css rules for the document
13251 * @param {Boolean} refreshCache true to refresh the internal cache
13252 * @return {Object} An object (hash) of rules indexed by selector
13254 getRules : function(refreshCache){
13255 if(rules == null || refreshCache){
13257 var ds = doc.styleSheets;
13258 for(var i =0, len = ds.length; i < len; i++){
13260 this.cacheStyleSheet(ds[i]);
13268 * Gets an an individual CSS rule by selector(s)
13269 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13270 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13271 * @return {CSSRule} The CSS rule or null if one is not found
13273 getRule : function(selector, refreshCache){
13274 var rs = this.getRules(refreshCache);
13275 if(!(selector instanceof Array)){
13276 return rs[selector];
13278 for(var i = 0; i < selector.length; i++){
13279 if(rs[selector[i]]){
13280 return rs[selector[i]];
13288 * Updates a rule property
13289 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13290 * @param {String} property The css property
13291 * @param {String} value The new value for the property
13292 * @return {Boolean} true If a rule was found and updated
13294 updateRule : function(selector, property, value){
13295 if(!(selector instanceof Array)){
13296 var rule = this.getRule(selector);
13298 rule.style[property.replace(camelRe, camelFn)] = value;
13302 for(var i = 0; i < selector.length; i++){
13303 if(this.updateRule(selector[i], property, value)){
13313 * Ext JS Library 1.1.1
13314 * Copyright(c) 2006-2007, Ext JS, LLC.
13316 * Originally Released Under LGPL - original licence link has changed is not relivant.
13319 * <script type="text/javascript">
13325 * @class Roo.util.ClickRepeater
13326 * @extends Roo.util.Observable
13328 * A wrapper class which can be applied to any element. Fires a "click" event while the
13329 * mouse is pressed. The interval between firings may be specified in the config but
13330 * defaults to 10 milliseconds.
13332 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13334 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13335 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13336 * Similar to an autorepeat key delay.
13337 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13338 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13339 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13340 * "interval" and "delay" are ignored. "immediate" is honored.
13341 * @cfg {Boolean} preventDefault True to prevent the default click event
13342 * @cfg {Boolean} stopDefault True to stop the default click event
13345 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13346 * 2007-02-02 jvs Renamed to ClickRepeater
13347 * 2007-02-03 jvs Modifications for FF Mac and Safari
13350 * @param {String/HTMLElement/Element} el The element to listen on
13351 * @param {Object} config
13353 Roo.util.ClickRepeater = function(el, config)
13355 this.el = Roo.get(el);
13356 this.el.unselectable();
13358 Roo.apply(this, config);
13363 * Fires when the mouse button is depressed.
13364 * @param {Roo.util.ClickRepeater} this
13366 "mousedown" : true,
13369 * Fires on a specified interval during the time the element is pressed.
13370 * @param {Roo.util.ClickRepeater} this
13375 * Fires when the mouse key is released.
13376 * @param {Roo.util.ClickRepeater} this
13381 this.el.on("mousedown", this.handleMouseDown, this);
13382 if(this.preventDefault || this.stopDefault){
13383 this.el.on("click", function(e){
13384 if(this.preventDefault){
13385 e.preventDefault();
13387 if(this.stopDefault){
13393 // allow inline handler
13395 this.on("click", this.handler, this.scope || this);
13398 Roo.util.ClickRepeater.superclass.constructor.call(this);
13401 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13404 preventDefault : true,
13405 stopDefault : false,
13409 handleMouseDown : function(){
13410 clearTimeout(this.timer);
13412 if(this.pressClass){
13413 this.el.addClass(this.pressClass);
13415 this.mousedownTime = new Date();
13417 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13418 this.el.on("mouseout", this.handleMouseOut, this);
13420 this.fireEvent("mousedown", this);
13421 this.fireEvent("click", this);
13423 this.timer = this.click.defer(this.delay || this.interval, this);
13427 click : function(){
13428 this.fireEvent("click", this);
13429 this.timer = this.click.defer(this.getInterval(), this);
13433 getInterval: function(){
13434 if(!this.accelerate){
13435 return this.interval;
13437 var pressTime = this.mousedownTime.getElapsed();
13438 if(pressTime < 500){
13440 }else if(pressTime < 1700){
13442 }else if(pressTime < 2600){
13444 }else if(pressTime < 3500){
13446 }else if(pressTime < 4400){
13448 }else if(pressTime < 5300){
13450 }else if(pressTime < 6200){
13458 handleMouseOut : function(){
13459 clearTimeout(this.timer);
13460 if(this.pressClass){
13461 this.el.removeClass(this.pressClass);
13463 this.el.on("mouseover", this.handleMouseReturn, this);
13467 handleMouseReturn : function(){
13468 this.el.un("mouseover", this.handleMouseReturn);
13469 if(this.pressClass){
13470 this.el.addClass(this.pressClass);
13476 handleMouseUp : function(){
13477 clearTimeout(this.timer);
13478 this.el.un("mouseover", this.handleMouseReturn);
13479 this.el.un("mouseout", this.handleMouseOut);
13480 Roo.get(document).un("mouseup", this.handleMouseUp);
13481 this.el.removeClass(this.pressClass);
13482 this.fireEvent("mouseup", this);
13486 * Ext JS Library 1.1.1
13487 * Copyright(c) 2006-2007, Ext JS, LLC.
13489 * Originally Released Under LGPL - original licence link has changed is not relivant.
13492 * <script type="text/javascript">
13497 * @class Roo.KeyNav
13498 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13499 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13500 * way to implement custom navigation schemes for any UI component.</p>
13501 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13502 * pageUp, pageDown, del, home, end. Usage:</p>
13504 var nav = new Roo.KeyNav("my-element", {
13505 "left" : function(e){
13506 this.moveLeft(e.ctrlKey);
13508 "right" : function(e){
13509 this.moveRight(e.ctrlKey);
13511 "enter" : function(e){
13518 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13519 * @param {Object} config The config
13521 Roo.KeyNav = function(el, config){
13522 this.el = Roo.get(el);
13523 Roo.apply(this, config);
13524 if(!this.disabled){
13525 this.disabled = true;
13530 Roo.KeyNav.prototype = {
13532 * @cfg {Boolean} disabled
13533 * True to disable this KeyNav instance (defaults to false)
13537 * @cfg {String} defaultEventAction
13538 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13539 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13540 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13542 defaultEventAction: "stopEvent",
13544 * @cfg {Boolean} forceKeyDown
13545 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13546 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13547 * handle keydown instead of keypress.
13549 forceKeyDown : false,
13552 prepareEvent : function(e){
13553 var k = e.getKey();
13554 var h = this.keyToHandler[k];
13555 //if(h && this[h]){
13556 // e.stopPropagation();
13558 if(Roo.isSafari && h && k >= 37 && k <= 40){
13564 relay : function(e){
13565 var k = e.getKey();
13566 var h = this.keyToHandler[k];
13568 if(this.doRelay(e, this[h], h) !== true){
13569 e[this.defaultEventAction]();
13575 doRelay : function(e, h, hname){
13576 return h.call(this.scope || this, e);
13579 // possible handlers
13593 // quick lookup hash
13610 * Enable this KeyNav
13612 enable: function(){
13614 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13615 // the EventObject will normalize Safari automatically
13616 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13617 this.el.on("keydown", this.relay, this);
13619 this.el.on("keydown", this.prepareEvent, this);
13620 this.el.on("keypress", this.relay, this);
13622 this.disabled = false;
13627 * Disable this KeyNav
13629 disable: function(){
13630 if(!this.disabled){
13631 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13632 this.el.un("keydown", this.relay);
13634 this.el.un("keydown", this.prepareEvent);
13635 this.el.un("keypress", this.relay);
13637 this.disabled = true;
13642 * Ext JS Library 1.1.1
13643 * Copyright(c) 2006-2007, Ext JS, LLC.
13645 * Originally Released Under LGPL - original licence link has changed is not relivant.
13648 * <script type="text/javascript">
13653 * @class Roo.KeyMap
13654 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13655 * The constructor accepts the same config object as defined by {@link #addBinding}.
13656 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13657 * combination it will call the function with this signature (if the match is a multi-key
13658 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13659 * A KeyMap can also handle a string representation of keys.<br />
13662 // map one key by key code
13663 var map = new Roo.KeyMap("my-element", {
13664 key: 13, // or Roo.EventObject.ENTER
13669 // map multiple keys to one action by string
13670 var map = new Roo.KeyMap("my-element", {
13676 // map multiple keys to multiple actions by strings and array of codes
13677 var map = new Roo.KeyMap("my-element", [
13680 fn: function(){ alert("Return was pressed"); }
13683 fn: function(){ alert('a, b or c was pressed'); }
13688 fn: function(){ alert('Control + shift + tab was pressed.'); }
13692 * <b>Note: A KeyMap starts enabled</b>
13694 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13695 * @param {Object} config The config (see {@link #addBinding})
13696 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13698 Roo.KeyMap = function(el, config, eventName){
13699 this.el = Roo.get(el);
13700 this.eventName = eventName || "keydown";
13701 this.bindings = [];
13703 this.addBinding(config);
13708 Roo.KeyMap.prototype = {
13710 * True to stop the event from bubbling and prevent the default browser action if the
13711 * key was handled by the KeyMap (defaults to false)
13717 * Add a new binding to this KeyMap. The following config object properties are supported:
13719 Property Type Description
13720 ---------- --------------- ----------------------------------------------------------------------
13721 key String/Array A single keycode or an array of keycodes to handle
13722 shift Boolean True to handle key only when shift is pressed (defaults to false)
13723 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13724 alt Boolean True to handle key only when alt is pressed (defaults to false)
13725 fn Function The function to call when KeyMap finds the expected key combination
13726 scope Object The scope of the callback function
13732 var map = new Roo.KeyMap(document, {
13733 key: Roo.EventObject.ENTER,
13738 //Add a new binding to the existing KeyMap later
13746 * @param {Object/Array} config A single KeyMap config or an array of configs
13748 addBinding : function(config){
13749 if(config instanceof Array){
13750 for(var i = 0, len = config.length; i < len; i++){
13751 this.addBinding(config[i]);
13755 var keyCode = config.key,
13756 shift = config.shift,
13757 ctrl = config.ctrl,
13760 scope = config.scope;
13761 if(typeof keyCode == "string"){
13763 var keyString = keyCode.toUpperCase();
13764 for(var j = 0, len = keyString.length; j < len; j++){
13765 ks.push(keyString.charCodeAt(j));
13769 var keyArray = keyCode instanceof Array;
13770 var handler = function(e){
13771 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13772 var k = e.getKey();
13774 for(var i = 0, len = keyCode.length; i < len; i++){
13775 if(keyCode[i] == k){
13776 if(this.stopEvent){
13779 fn.call(scope || window, k, e);
13785 if(this.stopEvent){
13788 fn.call(scope || window, k, e);
13793 this.bindings.push(handler);
13797 * Shorthand for adding a single key listener
13798 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13799 * following options:
13800 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13801 * @param {Function} fn The function to call
13802 * @param {Object} scope (optional) The scope of the function
13804 on : function(key, fn, scope){
13805 var keyCode, shift, ctrl, alt;
13806 if(typeof key == "object" && !(key instanceof Array)){
13825 handleKeyDown : function(e){
13826 if(this.enabled){ //just in case
13827 var b = this.bindings;
13828 for(var i = 0, len = b.length; i < len; i++){
13829 b[i].call(this, e);
13835 * Returns true if this KeyMap is enabled
13836 * @return {Boolean}
13838 isEnabled : function(){
13839 return this.enabled;
13843 * Enables this KeyMap
13845 enable: function(){
13847 this.el.on(this.eventName, this.handleKeyDown, this);
13848 this.enabled = true;
13853 * Disable this KeyMap
13855 disable: function(){
13857 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13858 this.enabled = false;
13863 * Ext JS Library 1.1.1
13864 * Copyright(c) 2006-2007, Ext JS, LLC.
13866 * Originally Released Under LGPL - original licence link has changed is not relivant.
13869 * <script type="text/javascript">
13874 * @class Roo.util.TextMetrics
13875 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13876 * wide, in pixels, a given block of text will be.
13879 Roo.util.TextMetrics = function(){
13883 * Measures the size of the specified text
13884 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13885 * that can affect the size of the rendered text
13886 * @param {String} text The text to measure
13887 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13888 * in order to accurately measure the text height
13889 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13891 measure : function(el, text, fixedWidth){
13893 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13896 shared.setFixedWidth(fixedWidth || 'auto');
13897 return shared.getSize(text);
13901 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13902 * the overhead of multiple calls to initialize the style properties on each measurement.
13903 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13904 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13905 * in order to accurately measure the text height
13906 * @return {Roo.util.TextMetrics.Instance} instance The new instance
13908 createInstance : function(el, fixedWidth){
13909 return Roo.util.TextMetrics.Instance(el, fixedWidth);
13916 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13917 var ml = new Roo.Element(document.createElement('div'));
13918 document.body.appendChild(ml.dom);
13919 ml.position('absolute');
13920 ml.setLeftTop(-1000, -1000);
13924 ml.setWidth(fixedWidth);
13929 * Returns the size of the specified text based on the internal element's style and width properties
13930 * @memberOf Roo.util.TextMetrics.Instance#
13931 * @param {String} text The text to measure
13932 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13934 getSize : function(text){
13936 var s = ml.getSize();
13942 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13943 * that can affect the size of the rendered text
13944 * @memberOf Roo.util.TextMetrics.Instance#
13945 * @param {String/HTMLElement} el The element, dom node or id
13947 bind : function(el){
13949 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13954 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
13955 * to set a fixed width in order to accurately measure the text height.
13956 * @memberOf Roo.util.TextMetrics.Instance#
13957 * @param {Number} width The width to set on the element
13959 setFixedWidth : function(width){
13960 ml.setWidth(width);
13964 * Returns the measured width of the specified text
13965 * @memberOf Roo.util.TextMetrics.Instance#
13966 * @param {String} text The text to measure
13967 * @return {Number} width The width in pixels
13969 getWidth : function(text){
13970 ml.dom.style.width = 'auto';
13971 return this.getSize(text).width;
13975 * Returns the measured height of the specified text. For multiline text, be sure to call
13976 * {@link #setFixedWidth} if necessary.
13977 * @memberOf Roo.util.TextMetrics.Instance#
13978 * @param {String} text The text to measure
13979 * @return {Number} height The height in pixels
13981 getHeight : function(text){
13982 return this.getSize(text).height;
13986 instance.bind(bindTo);
13991 // backwards compat
13992 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13994 * Ext JS Library 1.1.1
13995 * Copyright(c) 2006-2007, Ext JS, LLC.
13997 * Originally Released Under LGPL - original licence link has changed is not relivant.
14000 * <script type="text/javascript">
14004 * @class Roo.state.Provider
14005 * Abstract base class for state provider implementations. This class provides methods
14006 * for encoding and decoding <b>typed</b> variables including dates and defines the
14007 * Provider interface.
14009 Roo.state.Provider = function(){
14011 * @event statechange
14012 * Fires when a state change occurs.
14013 * @param {Provider} this This state provider
14014 * @param {String} key The state key which was changed
14015 * @param {String} value The encoded value for the state
14018 "statechange": true
14021 Roo.state.Provider.superclass.constructor.call(this);
14023 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14025 * Returns the current value for a key
14026 * @param {String} name The key name
14027 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14028 * @return {Mixed} The state data
14030 get : function(name, defaultValue){
14031 return typeof this.state[name] == "undefined" ?
14032 defaultValue : this.state[name];
14036 * Clears a value from the state
14037 * @param {String} name The key name
14039 clear : function(name){
14040 delete this.state[name];
14041 this.fireEvent("statechange", this, name, null);
14045 * Sets the value for a key
14046 * @param {String} name The key name
14047 * @param {Mixed} value The value to set
14049 set : function(name, value){
14050 this.state[name] = value;
14051 this.fireEvent("statechange", this, name, value);
14055 * Decodes a string previously encoded with {@link #encodeValue}.
14056 * @param {String} value The value to decode
14057 * @return {Mixed} The decoded value
14059 decodeValue : function(cookie){
14060 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14061 var matches = re.exec(unescape(cookie));
14062 if(!matches || !matches[1]) return; // non state cookie
14063 var type = matches[1];
14064 var v = matches[2];
14067 return parseFloat(v);
14069 return new Date(Date.parse(v));
14074 var values = v.split("^");
14075 for(var i = 0, len = values.length; i < len; i++){
14076 all.push(this.decodeValue(values[i]));
14081 var values = v.split("^");
14082 for(var i = 0, len = values.length; i < len; i++){
14083 var kv = values[i].split("=");
14084 all[kv[0]] = this.decodeValue(kv[1]);
14093 * Encodes a value including type information. Decode with {@link #decodeValue}.
14094 * @param {Mixed} value The value to encode
14095 * @return {String} The encoded value
14097 encodeValue : function(v){
14099 if(typeof v == "number"){
14101 }else if(typeof v == "boolean"){
14102 enc = "b:" + (v ? "1" : "0");
14103 }else if(v instanceof Date){
14104 enc = "d:" + v.toGMTString();
14105 }else if(v instanceof Array){
14107 for(var i = 0, len = v.length; i < len; i++){
14108 flat += this.encodeValue(v[i]);
14109 if(i != len-1) flat += "^";
14112 }else if(typeof v == "object"){
14115 if(typeof v[key] != "function"){
14116 flat += key + "=" + this.encodeValue(v[key]) + "^";
14119 enc = "o:" + flat.substring(0, flat.length-1);
14123 return escape(enc);
14129 * Ext JS Library 1.1.1
14130 * Copyright(c) 2006-2007, Ext JS, LLC.
14132 * Originally Released Under LGPL - original licence link has changed is not relivant.
14135 * <script type="text/javascript">
14138 * @class Roo.state.Manager
14139 * This is the global state manager. By default all components that are "state aware" check this class
14140 * for state information if you don't pass them a custom state provider. In order for this class
14141 * to be useful, it must be initialized with a provider when your application initializes.
14143 // in your initialization function
14145 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14147 // supposed you have a {@link Roo.BorderLayout}
14148 var layout = new Roo.BorderLayout(...);
14149 layout.restoreState();
14150 // or a {Roo.BasicDialog}
14151 var dialog = new Roo.BasicDialog(...);
14152 dialog.restoreState();
14156 Roo.state.Manager = function(){
14157 var provider = new Roo.state.Provider();
14161 * Configures the default state provider for your application
14162 * @param {Provider} stateProvider The state provider to set
14164 setProvider : function(stateProvider){
14165 provider = stateProvider;
14169 * Returns the current value for a key
14170 * @param {String} name The key name
14171 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14172 * @return {Mixed} The state data
14174 get : function(key, defaultValue){
14175 return provider.get(key, defaultValue);
14179 * Sets the value for a key
14180 * @param {String} name The key name
14181 * @param {Mixed} value The state data
14183 set : function(key, value){
14184 provider.set(key, value);
14188 * Clears a value from the state
14189 * @param {String} name The key name
14191 clear : function(key){
14192 provider.clear(key);
14196 * Gets the currently configured state provider
14197 * @return {Provider} The state provider
14199 getProvider : function(){
14206 * Ext JS Library 1.1.1
14207 * Copyright(c) 2006-2007, Ext JS, LLC.
14209 * Originally Released Under LGPL - original licence link has changed is not relivant.
14212 * <script type="text/javascript">
14215 * @class Roo.state.CookieProvider
14216 * @extends Roo.state.Provider
14217 * The default Provider implementation which saves state via cookies.
14220 var cp = new Roo.state.CookieProvider({
14222 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14223 domain: "roojs.com"
14225 Roo.state.Manager.setProvider(cp);
14227 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14228 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14229 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14230 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14231 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14232 * domain the page is running on including the 'www' like 'www.roojs.com')
14233 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14235 * Create a new CookieProvider
14236 * @param {Object} config The configuration object
14238 Roo.state.CookieProvider = function(config){
14239 Roo.state.CookieProvider.superclass.constructor.call(this);
14241 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14242 this.domain = null;
14243 this.secure = false;
14244 Roo.apply(this, config);
14245 this.state = this.readCookies();
14248 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14250 set : function(name, value){
14251 if(typeof value == "undefined" || value === null){
14255 this.setCookie(name, value);
14256 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14260 clear : function(name){
14261 this.clearCookie(name);
14262 Roo.state.CookieProvider.superclass.clear.call(this, name);
14266 readCookies : function(){
14268 var c = document.cookie + ";";
14269 var re = /\s?(.*?)=(.*?);/g;
14271 while((matches = re.exec(c)) != null){
14272 var name = matches[1];
14273 var value = matches[2];
14274 if(name && name.substring(0,3) == "ys-"){
14275 cookies[name.substr(3)] = this.decodeValue(value);
14282 setCookie : function(name, value){
14283 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14284 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14285 ((this.path == null) ? "" : ("; path=" + this.path)) +
14286 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14287 ((this.secure == true) ? "; secure" : "");
14291 clearCookie : function(name){
14292 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14293 ((this.path == null) ? "" : ("; path=" + this.path)) +
14294 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14295 ((this.secure == true) ? "; secure" : "");
14299 * Ext JS Library 1.1.1
14300 * Copyright(c) 2006-2007, Ext JS, LLC.
14302 * Originally Released Under LGPL - original licence link has changed is not relivant.
14305 * <script type="text/javascript">
14311 * These classes are derivatives of the similarly named classes in the YUI Library.
14312 * The original license:
14313 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14314 * Code licensed under the BSD License:
14315 * http://developer.yahoo.net/yui/license.txt
14320 var Event=Roo.EventManager;
14321 var Dom=Roo.lib.Dom;
14324 * @class Roo.dd.DragDrop
14325 * Defines the interface and base operation of items that that can be
14326 * dragged or can be drop targets. It was designed to be extended, overriding
14327 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14328 * Up to three html elements can be associated with a DragDrop instance:
14330 * <li>linked element: the element that is passed into the constructor.
14331 * This is the element which defines the boundaries for interaction with
14332 * other DragDrop objects.</li>
14333 * <li>handle element(s): The drag operation only occurs if the element that
14334 * was clicked matches a handle element. By default this is the linked
14335 * element, but there are times that you will want only a portion of the
14336 * linked element to initiate the drag operation, and the setHandleElId()
14337 * method provides a way to define this.</li>
14338 * <li>drag element: this represents the element that would be moved along
14339 * with the cursor during a drag operation. By default, this is the linked
14340 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14341 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14344 * This class should not be instantiated until the onload event to ensure that
14345 * the associated elements are available.
14346 * The following would define a DragDrop obj that would interact with any
14347 * other DragDrop obj in the "group1" group:
14349 * dd = new Roo.dd.DragDrop("div1", "group1");
14351 * Since none of the event handlers have been implemented, nothing would
14352 * actually happen if you were to run the code above. Normally you would
14353 * override this class or one of the default implementations, but you can
14354 * also override the methods you want on an instance of the class...
14356 * dd.onDragDrop = function(e, id) {
14357 * alert("dd was dropped on " + id);
14361 * @param {String} id of the element that is linked to this instance
14362 * @param {String} sGroup the group of related DragDrop objects
14363 * @param {object} config an object containing configurable attributes
14364 * Valid properties for DragDrop:
14365 * padding, isTarget, maintainOffset, primaryButtonOnly
14367 Roo.dd.DragDrop = function(id, sGroup, config) {
14369 this.init(id, sGroup, config);
14373 Roo.dd.DragDrop.prototype = {
14376 * The id of the element associated with this object. This is what we
14377 * refer to as the "linked element" because the size and position of
14378 * this element is used to determine when the drag and drop objects have
14386 * Configuration attributes passed into the constructor
14393 * The id of the element that will be dragged. By default this is same
14394 * as the linked element , but could be changed to another element. Ex:
14396 * @property dragElId
14403 * the id of the element that initiates the drag operation. By default
14404 * this is the linked element, but could be changed to be a child of this
14405 * element. This lets us do things like only starting the drag when the
14406 * header element within the linked html element is clicked.
14407 * @property handleElId
14414 * An associative array of HTML tags that will be ignored if clicked.
14415 * @property invalidHandleTypes
14416 * @type {string: string}
14418 invalidHandleTypes: null,
14421 * An associative array of ids for elements that will be ignored if clicked
14422 * @property invalidHandleIds
14423 * @type {string: string}
14425 invalidHandleIds: null,
14428 * An indexted array of css class names for elements that will be ignored
14430 * @property invalidHandleClasses
14433 invalidHandleClasses: null,
14436 * The linked element's absolute X position at the time the drag was
14438 * @property startPageX
14445 * The linked element's absolute X position at the time the drag was
14447 * @property startPageY
14454 * The group defines a logical collection of DragDrop objects that are
14455 * related. Instances only get events when interacting with other
14456 * DragDrop object in the same group. This lets us define multiple
14457 * groups using a single DragDrop subclass if we want.
14459 * @type {string: string}
14464 * Individual drag/drop instances can be locked. This will prevent
14465 * onmousedown start drag.
14473 * Lock this instance
14476 lock: function() { this.locked = true; },
14479 * Unlock this instace
14482 unlock: function() { this.locked = false; },
14485 * By default, all insances can be a drop target. This can be disabled by
14486 * setting isTarget to false.
14493 * The padding configured for this drag and drop object for calculating
14494 * the drop zone intersection with this object.
14501 * Cached reference to the linked element
14502 * @property _domRef
14508 * Internal typeof flag
14509 * @property __ygDragDrop
14512 __ygDragDrop: true,
14515 * Set to true when horizontal contraints are applied
14516 * @property constrainX
14523 * Set to true when vertical contraints are applied
14524 * @property constrainY
14531 * The left constraint
14539 * The right constraint
14547 * The up constraint
14556 * The down constraint
14564 * Maintain offsets when we resetconstraints. Set to true when you want
14565 * the position of the element relative to its parent to stay the same
14566 * when the page changes
14568 * @property maintainOffset
14571 maintainOffset: false,
14574 * Array of pixel locations the element will snap to if we specified a
14575 * horizontal graduation/interval. This array is generated automatically
14576 * when you define a tick interval.
14583 * Array of pixel locations the element will snap to if we specified a
14584 * vertical graduation/interval. This array is generated automatically
14585 * when you define a tick interval.
14592 * By default the drag and drop instance will only respond to the primary
14593 * button click (left button for a right-handed mouse). Set to true to
14594 * allow drag and drop to start with any mouse click that is propogated
14596 * @property primaryButtonOnly
14599 primaryButtonOnly: true,
14602 * The availabe property is false until the linked dom element is accessible.
14603 * @property available
14609 * By default, drags can only be initiated if the mousedown occurs in the
14610 * region the linked element is. This is done in part to work around a
14611 * bug in some browsers that mis-report the mousedown if the previous
14612 * mouseup happened outside of the window. This property is set to true
14613 * if outer handles are defined.
14615 * @property hasOuterHandles
14619 hasOuterHandles: false,
14622 * Code that executes immediately before the startDrag event
14623 * @method b4StartDrag
14626 b4StartDrag: function(x, y) { },
14629 * Abstract method called after a drag/drop object is clicked
14630 * and the drag or mousedown time thresholds have beeen met.
14631 * @method startDrag
14632 * @param {int} X click location
14633 * @param {int} Y click location
14635 startDrag: function(x, y) { /* override this */ },
14638 * Code that executes immediately before the onDrag event
14642 b4Drag: function(e) { },
14645 * Abstract method called during the onMouseMove event while dragging an
14648 * @param {Event} e the mousemove event
14650 onDrag: function(e) { /* override this */ },
14653 * Abstract method called when this element fist begins hovering over
14654 * another DragDrop obj
14655 * @method onDragEnter
14656 * @param {Event} e the mousemove event
14657 * @param {String|DragDrop[]} id In POINT mode, the element
14658 * id this is hovering over. In INTERSECT mode, an array of one or more
14659 * dragdrop items being hovered over.
14661 onDragEnter: function(e, id) { /* override this */ },
14664 * Code that executes immediately before the onDragOver event
14665 * @method b4DragOver
14668 b4DragOver: function(e) { },
14671 * Abstract method called when this element is hovering over another
14673 * @method onDragOver
14674 * @param {Event} e the mousemove event
14675 * @param {String|DragDrop[]} id In POINT mode, the element
14676 * id this is hovering over. In INTERSECT mode, an array of dd items
14677 * being hovered over.
14679 onDragOver: function(e, id) { /* override this */ },
14682 * Code that executes immediately before the onDragOut event
14683 * @method b4DragOut
14686 b4DragOut: function(e) { },
14689 * Abstract method called when we are no longer hovering over an element
14690 * @method onDragOut
14691 * @param {Event} e the mousemove event
14692 * @param {String|DragDrop[]} id In POINT mode, the element
14693 * id this was hovering over. In INTERSECT mode, an array of dd items
14694 * that the mouse is no longer over.
14696 onDragOut: function(e, id) { /* override this */ },
14699 * Code that executes immediately before the onDragDrop event
14700 * @method b4DragDrop
14703 b4DragDrop: function(e) { },
14706 * Abstract method called when this item is dropped on another DragDrop
14708 * @method onDragDrop
14709 * @param {Event} e the mouseup event
14710 * @param {String|DragDrop[]} id In POINT mode, the element
14711 * id this was dropped on. In INTERSECT mode, an array of dd items this
14714 onDragDrop: function(e, id) { /* override this */ },
14717 * Abstract method called when this item is dropped on an area with no
14719 * @method onInvalidDrop
14720 * @param {Event} e the mouseup event
14722 onInvalidDrop: function(e) { /* override this */ },
14725 * Code that executes immediately before the endDrag event
14726 * @method b4EndDrag
14729 b4EndDrag: function(e) { },
14732 * Fired when we are done dragging the object
14734 * @param {Event} e the mouseup event
14736 endDrag: function(e) { /* override this */ },
14739 * Code executed immediately before the onMouseDown event
14740 * @method b4MouseDown
14741 * @param {Event} e the mousedown event
14744 b4MouseDown: function(e) { },
14747 * Event handler that fires when a drag/drop obj gets a mousedown
14748 * @method onMouseDown
14749 * @param {Event} e the mousedown event
14751 onMouseDown: function(e) { /* override this */ },
14754 * Event handler that fires when a drag/drop obj gets a mouseup
14755 * @method onMouseUp
14756 * @param {Event} e the mouseup event
14758 onMouseUp: function(e) { /* override this */ },
14761 * Override the onAvailable method to do what is needed after the initial
14762 * position was determined.
14763 * @method onAvailable
14765 onAvailable: function () {
14769 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14772 defaultPadding : {left:0, right:0, top:0, bottom:0},
14775 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14779 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14780 { dragElId: "existingProxyDiv" });
14781 dd.startDrag = function(){
14782 this.constrainTo("parent-id");
14785 * Or you can initalize it using the {@link Roo.Element} object:
14787 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14788 startDrag : function(){
14789 this.constrainTo("parent-id");
14793 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14794 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14795 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14796 * an object containing the sides to pad. For example: {right:10, bottom:10}
14797 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14799 constrainTo : function(constrainTo, pad, inContent){
14800 if(typeof pad == "number"){
14801 pad = {left: pad, right:pad, top:pad, bottom:pad};
14803 pad = pad || this.defaultPadding;
14804 var b = Roo.get(this.getEl()).getBox();
14805 var ce = Roo.get(constrainTo);
14806 var s = ce.getScroll();
14807 var c, cd = ce.dom;
14808 if(cd == document.body){
14809 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14812 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14816 var topSpace = b.y - c.y;
14817 var leftSpace = b.x - c.x;
14819 this.resetConstraints();
14820 this.setXConstraint(leftSpace - (pad.left||0), // left
14821 c.width - leftSpace - b.width - (pad.right||0) //right
14823 this.setYConstraint(topSpace - (pad.top||0), //top
14824 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14829 * Returns a reference to the linked element
14831 * @return {HTMLElement} the html element
14833 getEl: function() {
14834 if (!this._domRef) {
14835 this._domRef = Roo.getDom(this.id);
14838 return this._domRef;
14842 * Returns a reference to the actual element to drag. By default this is
14843 * the same as the html element, but it can be assigned to another
14844 * element. An example of this can be found in Roo.dd.DDProxy
14845 * @method getDragEl
14846 * @return {HTMLElement} the html element
14848 getDragEl: function() {
14849 return Roo.getDom(this.dragElId);
14853 * Sets up the DragDrop object. Must be called in the constructor of any
14854 * Roo.dd.DragDrop subclass
14856 * @param id the id of the linked element
14857 * @param {String} sGroup the group of related items
14858 * @param {object} config configuration attributes
14860 init: function(id, sGroup, config) {
14861 this.initTarget(id, sGroup, config);
14862 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14863 // Event.on(this.id, "selectstart", Event.preventDefault);
14867 * Initializes Targeting functionality only... the object does not
14868 * get a mousedown handler.
14869 * @method initTarget
14870 * @param id the id of the linked element
14871 * @param {String} sGroup the group of related items
14872 * @param {object} config configuration attributes
14874 initTarget: function(id, sGroup, config) {
14876 // configuration attributes
14877 this.config = config || {};
14879 // create a local reference to the drag and drop manager
14880 this.DDM = Roo.dd.DDM;
14881 // initialize the groups array
14884 // assume that we have an element reference instead of an id if the
14885 // parameter is not a string
14886 if (typeof id !== "string") {
14893 // add to an interaction group
14894 this.addToGroup((sGroup) ? sGroup : "default");
14896 // We don't want to register this as the handle with the manager
14897 // so we just set the id rather than calling the setter.
14898 this.handleElId = id;
14900 // the linked element is the element that gets dragged by default
14901 this.setDragElId(id);
14903 // by default, clicked anchors will not start drag operations.
14904 this.invalidHandleTypes = { A: "A" };
14905 this.invalidHandleIds = {};
14906 this.invalidHandleClasses = [];
14908 this.applyConfig();
14910 this.handleOnAvailable();
14914 * Applies the configuration parameters that were passed into the constructor.
14915 * This is supposed to happen at each level through the inheritance chain. So
14916 * a DDProxy implentation will execute apply config on DDProxy, DD, and
14917 * DragDrop in order to get all of the parameters that are available in
14919 * @method applyConfig
14921 applyConfig: function() {
14923 // configurable properties:
14924 // padding, isTarget, maintainOffset, primaryButtonOnly
14925 this.padding = this.config.padding || [0, 0, 0, 0];
14926 this.isTarget = (this.config.isTarget !== false);
14927 this.maintainOffset = (this.config.maintainOffset);
14928 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
14933 * Executed when the linked element is available
14934 * @method handleOnAvailable
14937 handleOnAvailable: function() {
14938 this.available = true;
14939 this.resetConstraints();
14940 this.onAvailable();
14944 * Configures the padding for the target zone in px. Effectively expands
14945 * (or reduces) the virtual object size for targeting calculations.
14946 * Supports css-style shorthand; if only one parameter is passed, all sides
14947 * will have that padding, and if only two are passed, the top and bottom
14948 * will have the first param, the left and right the second.
14949 * @method setPadding
14950 * @param {int} iTop Top pad
14951 * @param {int} iRight Right pad
14952 * @param {int} iBot Bot pad
14953 * @param {int} iLeft Left pad
14955 setPadding: function(iTop, iRight, iBot, iLeft) {
14956 // this.padding = [iLeft, iRight, iTop, iBot];
14957 if (!iRight && 0 !== iRight) {
14958 this.padding = [iTop, iTop, iTop, iTop];
14959 } else if (!iBot && 0 !== iBot) {
14960 this.padding = [iTop, iRight, iTop, iRight];
14962 this.padding = [iTop, iRight, iBot, iLeft];
14967 * Stores the initial placement of the linked element.
14968 * @method setInitialPosition
14969 * @param {int} diffX the X offset, default 0
14970 * @param {int} diffY the Y offset, default 0
14972 setInitPosition: function(diffX, diffY) {
14973 var el = this.getEl();
14975 if (!this.DDM.verifyEl(el)) {
14979 var dx = diffX || 0;
14980 var dy = diffY || 0;
14982 var p = Dom.getXY( el );
14984 this.initPageX = p[0] - dx;
14985 this.initPageY = p[1] - dy;
14987 this.lastPageX = p[0];
14988 this.lastPageY = p[1];
14991 this.setStartPosition(p);
14995 * Sets the start position of the element. This is set when the obj
14996 * is initialized, the reset when a drag is started.
14997 * @method setStartPosition
14998 * @param pos current position (from previous lookup)
15001 setStartPosition: function(pos) {
15002 var p = pos || Dom.getXY( this.getEl() );
15003 this.deltaSetXY = null;
15005 this.startPageX = p[0];
15006 this.startPageY = p[1];
15010 * Add this instance to a group of related drag/drop objects. All
15011 * instances belong to at least one group, and can belong to as many
15012 * groups as needed.
15013 * @method addToGroup
15014 * @param sGroup {string} the name of the group
15016 addToGroup: function(sGroup) {
15017 this.groups[sGroup] = true;
15018 this.DDM.regDragDrop(this, sGroup);
15022 * Remove's this instance from the supplied interaction group
15023 * @method removeFromGroup
15024 * @param {string} sGroup The group to drop
15026 removeFromGroup: function(sGroup) {
15027 if (this.groups[sGroup]) {
15028 delete this.groups[sGroup];
15031 this.DDM.removeDDFromGroup(this, sGroup);
15035 * Allows you to specify that an element other than the linked element
15036 * will be moved with the cursor during a drag
15037 * @method setDragElId
15038 * @param id {string} the id of the element that will be used to initiate the drag
15040 setDragElId: function(id) {
15041 this.dragElId = id;
15045 * Allows you to specify a child of the linked element that should be
15046 * used to initiate the drag operation. An example of this would be if
15047 * you have a content div with text and links. Clicking anywhere in the
15048 * content area would normally start the drag operation. Use this method
15049 * to specify that an element inside of the content div is the element
15050 * that starts the drag operation.
15051 * @method setHandleElId
15052 * @param id {string} the id of the element that will be used to
15053 * initiate the drag.
15055 setHandleElId: function(id) {
15056 if (typeof id !== "string") {
15059 this.handleElId = id;
15060 this.DDM.regHandle(this.id, id);
15064 * Allows you to set an element outside of the linked element as a drag
15066 * @method setOuterHandleElId
15067 * @param id the id of the element that will be used to initiate the drag
15069 setOuterHandleElId: function(id) {
15070 if (typeof id !== "string") {
15073 Event.on(id, "mousedown",
15074 this.handleMouseDown, this);
15075 this.setHandleElId(id);
15077 this.hasOuterHandles = true;
15081 * Remove all drag and drop hooks for this element
15084 unreg: function() {
15085 Event.un(this.id, "mousedown",
15086 this.handleMouseDown);
15087 this._domRef = null;
15088 this.DDM._remove(this);
15091 destroy : function(){
15096 * Returns true if this instance is locked, or the drag drop mgr is locked
15097 * (meaning that all drag/drop is disabled on the page.)
15099 * @return {boolean} true if this obj or all drag/drop is locked, else
15102 isLocked: function() {
15103 return (this.DDM.isLocked() || this.locked);
15107 * Fired when this object is clicked
15108 * @method handleMouseDown
15110 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15113 handleMouseDown: function(e, oDD){
15114 if (this.primaryButtonOnly && e.button != 0) {
15118 if (this.isLocked()) {
15122 this.DDM.refreshCache(this.groups);
15124 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15125 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15127 if (this.clickValidator(e)) {
15129 // set the initial element position
15130 this.setStartPosition();
15133 this.b4MouseDown(e);
15134 this.onMouseDown(e);
15136 this.DDM.handleMouseDown(e, this);
15138 this.DDM.stopEvent(e);
15146 clickValidator: function(e) {
15147 var target = e.getTarget();
15148 return ( this.isValidHandleChild(target) &&
15149 (this.id == this.handleElId ||
15150 this.DDM.handleWasClicked(target, this.id)) );
15154 * Allows you to specify a tag name that should not start a drag operation
15155 * when clicked. This is designed to facilitate embedding links within a
15156 * drag handle that do something other than start the drag.
15157 * @method addInvalidHandleType
15158 * @param {string} tagName the type of element to exclude
15160 addInvalidHandleType: function(tagName) {
15161 var type = tagName.toUpperCase();
15162 this.invalidHandleTypes[type] = type;
15166 * Lets you to specify an element id for a child of a drag handle
15167 * that should not initiate a drag
15168 * @method addInvalidHandleId
15169 * @param {string} id the element id of the element you wish to ignore
15171 addInvalidHandleId: function(id) {
15172 if (typeof id !== "string") {
15175 this.invalidHandleIds[id] = id;
15179 * Lets you specify a css class of elements that will not initiate a drag
15180 * @method addInvalidHandleClass
15181 * @param {string} cssClass the class of the elements you wish to ignore
15183 addInvalidHandleClass: function(cssClass) {
15184 this.invalidHandleClasses.push(cssClass);
15188 * Unsets an excluded tag name set by addInvalidHandleType
15189 * @method removeInvalidHandleType
15190 * @param {string} tagName the type of element to unexclude
15192 removeInvalidHandleType: function(tagName) {
15193 var type = tagName.toUpperCase();
15194 // this.invalidHandleTypes[type] = null;
15195 delete this.invalidHandleTypes[type];
15199 * Unsets an invalid handle id
15200 * @method removeInvalidHandleId
15201 * @param {string} id the id of the element to re-enable
15203 removeInvalidHandleId: function(id) {
15204 if (typeof id !== "string") {
15207 delete this.invalidHandleIds[id];
15211 * Unsets an invalid css class
15212 * @method removeInvalidHandleClass
15213 * @param {string} cssClass the class of the element(s) you wish to
15216 removeInvalidHandleClass: function(cssClass) {
15217 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15218 if (this.invalidHandleClasses[i] == cssClass) {
15219 delete this.invalidHandleClasses[i];
15225 * Checks the tag exclusion list to see if this click should be ignored
15226 * @method isValidHandleChild
15227 * @param {HTMLElement} node the HTMLElement to evaluate
15228 * @return {boolean} true if this is a valid tag type, false if not
15230 isValidHandleChild: function(node) {
15233 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15236 nodeName = node.nodeName.toUpperCase();
15238 nodeName = node.nodeName;
15240 valid = valid && !this.invalidHandleTypes[nodeName];
15241 valid = valid && !this.invalidHandleIds[node.id];
15243 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15244 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15253 * Create the array of horizontal tick marks if an interval was specified
15254 * in setXConstraint().
15255 * @method setXTicks
15258 setXTicks: function(iStartX, iTickSize) {
15260 this.xTickSize = iTickSize;
15264 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15266 this.xTicks[this.xTicks.length] = i;
15271 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15273 this.xTicks[this.xTicks.length] = i;
15278 this.xTicks.sort(this.DDM.numericSort) ;
15282 * Create the array of vertical tick marks if an interval was specified in
15283 * setYConstraint().
15284 * @method setYTicks
15287 setYTicks: function(iStartY, iTickSize) {
15289 this.yTickSize = iTickSize;
15293 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15295 this.yTicks[this.yTicks.length] = i;
15300 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15302 this.yTicks[this.yTicks.length] = i;
15307 this.yTicks.sort(this.DDM.numericSort) ;
15311 * By default, the element can be dragged any place on the screen. Use
15312 * this method to limit the horizontal travel of the element. Pass in
15313 * 0,0 for the parameters if you want to lock the drag to the y axis.
15314 * @method setXConstraint
15315 * @param {int} iLeft the number of pixels the element can move to the left
15316 * @param {int} iRight the number of pixels the element can move to the
15318 * @param {int} iTickSize optional parameter for specifying that the
15320 * should move iTickSize pixels at a time.
15322 setXConstraint: function(iLeft, iRight, iTickSize) {
15323 this.leftConstraint = iLeft;
15324 this.rightConstraint = iRight;
15326 this.minX = this.initPageX - iLeft;
15327 this.maxX = this.initPageX + iRight;
15328 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15330 this.constrainX = true;
15334 * Clears any constraints applied to this instance. Also clears ticks
15335 * since they can't exist independent of a constraint at this time.
15336 * @method clearConstraints
15338 clearConstraints: function() {
15339 this.constrainX = false;
15340 this.constrainY = false;
15345 * Clears any tick interval defined for this instance
15346 * @method clearTicks
15348 clearTicks: function() {
15349 this.xTicks = null;
15350 this.yTicks = null;
15351 this.xTickSize = 0;
15352 this.yTickSize = 0;
15356 * By default, the element can be dragged any place on the screen. Set
15357 * this to limit the vertical travel of the element. Pass in 0,0 for the
15358 * parameters if you want to lock the drag to the x axis.
15359 * @method setYConstraint
15360 * @param {int} iUp the number of pixels the element can move up
15361 * @param {int} iDown the number of pixels the element can move down
15362 * @param {int} iTickSize optional parameter for specifying that the
15363 * element should move iTickSize pixels at a time.
15365 setYConstraint: function(iUp, iDown, iTickSize) {
15366 this.topConstraint = iUp;
15367 this.bottomConstraint = iDown;
15369 this.minY = this.initPageY - iUp;
15370 this.maxY = this.initPageY + iDown;
15371 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15373 this.constrainY = true;
15378 * resetConstraints must be called if you manually reposition a dd element.
15379 * @method resetConstraints
15380 * @param {boolean} maintainOffset
15382 resetConstraints: function() {
15385 // Maintain offsets if necessary
15386 if (this.initPageX || this.initPageX === 0) {
15387 // figure out how much this thing has moved
15388 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15389 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15391 this.setInitPosition(dx, dy);
15393 // This is the first time we have detected the element's position
15395 this.setInitPosition();
15398 if (this.constrainX) {
15399 this.setXConstraint( this.leftConstraint,
15400 this.rightConstraint,
15404 if (this.constrainY) {
15405 this.setYConstraint( this.topConstraint,
15406 this.bottomConstraint,
15412 * Normally the drag element is moved pixel by pixel, but we can specify
15413 * that it move a number of pixels at a time. This method resolves the
15414 * location when we have it set up like this.
15416 * @param {int} val where we want to place the object
15417 * @param {int[]} tickArray sorted array of valid points
15418 * @return {int} the closest tick
15421 getTick: function(val, tickArray) {
15424 // If tick interval is not defined, it is effectively 1 pixel,
15425 // so we return the value passed to us.
15427 } else if (tickArray[0] >= val) {
15428 // The value is lower than the first tick, so we return the first
15430 return tickArray[0];
15432 for (var i=0, len=tickArray.length; i<len; ++i) {
15434 if (tickArray[next] && tickArray[next] >= val) {
15435 var diff1 = val - tickArray[i];
15436 var diff2 = tickArray[next] - val;
15437 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15441 // The value is larger than the last tick, so we return the last
15443 return tickArray[tickArray.length - 1];
15450 * @return {string} string representation of the dd obj
15452 toString: function() {
15453 return ("DragDrop " + this.id);
15461 * Ext JS Library 1.1.1
15462 * Copyright(c) 2006-2007, Ext JS, LLC.
15464 * Originally Released Under LGPL - original licence link has changed is not relivant.
15467 * <script type="text/javascript">
15472 * The drag and drop utility provides a framework for building drag and drop
15473 * applications. In addition to enabling drag and drop for specific elements,
15474 * the drag and drop elements are tracked by the manager class, and the
15475 * interactions between the various elements are tracked during the drag and
15476 * the implementing code is notified about these important moments.
15479 // Only load the library once. Rewriting the manager class would orphan
15480 // existing drag and drop instances.
15481 if (!Roo.dd.DragDropMgr) {
15484 * @class Roo.dd.DragDropMgr
15485 * DragDropMgr is a singleton that tracks the element interaction for
15486 * all DragDrop items in the window. Generally, you will not call
15487 * this class directly, but it does have helper methods that could
15488 * be useful in your DragDrop implementations.
15491 Roo.dd.DragDropMgr = function() {
15493 var Event = Roo.EventManager;
15498 * Two dimensional Array of registered DragDrop objects. The first
15499 * dimension is the DragDrop item group, the second the DragDrop
15502 * @type {string: string}
15509 * Array of element ids defined as drag handles. Used to determine
15510 * if the element that generated the mousedown event is actually the
15511 * handle and not the html element itself.
15512 * @property handleIds
15513 * @type {string: string}
15520 * the DragDrop object that is currently being dragged
15521 * @property dragCurrent
15529 * the DragDrop object(s) that are being hovered over
15530 * @property dragOvers
15538 * the X distance between the cursor and the object being dragged
15547 * the Y distance between the cursor and the object being dragged
15556 * Flag to determine if we should prevent the default behavior of the
15557 * events we define. By default this is true, but this can be set to
15558 * false if you need the default behavior (not recommended)
15559 * @property preventDefault
15563 preventDefault: true,
15566 * Flag to determine if we should stop the propagation of the events
15567 * we generate. This is true by default but you may want to set it to
15568 * false if the html element contains other features that require the
15570 * @property stopPropagation
15574 stopPropagation: true,
15577 * Internal flag that is set to true when drag and drop has been
15579 * @property initialized
15586 * All drag and drop can be disabled.
15594 * Called the first time an element is registered.
15600 this.initialized = true;
15604 * In point mode, drag and drop interaction is defined by the
15605 * location of the cursor during the drag/drop
15613 * In intersect mode, drag and drop interactio nis defined by the
15614 * overlap of two or more drag and drop objects.
15615 * @property INTERSECT
15622 * The current drag and drop mode. Default: POINT
15630 * Runs method on all drag and drop objects
15631 * @method _execOnAll
15635 _execOnAll: function(sMethod, args) {
15636 for (var i in this.ids) {
15637 for (var j in this.ids[i]) {
15638 var oDD = this.ids[i][j];
15639 if (! this.isTypeOfDD(oDD)) {
15642 oDD[sMethod].apply(oDD, args);
15648 * Drag and drop initialization. Sets up the global event handlers
15653 _onLoad: function() {
15658 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15659 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15660 Event.on(window, "unload", this._onUnload, this, true);
15661 Event.on(window, "resize", this._onResize, this, true);
15662 // Event.on(window, "mouseout", this._test);
15667 * Reset constraints on all drag and drop objs
15668 * @method _onResize
15672 _onResize: function(e) {
15673 this._execOnAll("resetConstraints", []);
15677 * Lock all drag and drop functionality
15681 lock: function() { this.locked = true; },
15684 * Unlock all drag and drop functionality
15688 unlock: function() { this.locked = false; },
15691 * Is drag and drop locked?
15693 * @return {boolean} True if drag and drop is locked, false otherwise.
15696 isLocked: function() { return this.locked; },
15699 * Location cache that is set for all drag drop objects when a drag is
15700 * initiated, cleared when the drag is finished.
15701 * @property locationCache
15708 * Set useCache to false if you want to force object the lookup of each
15709 * drag and drop linked element constantly during a drag.
15710 * @property useCache
15717 * The number of pixels that the mouse needs to move after the
15718 * mousedown before the drag is initiated. Default=3;
15719 * @property clickPixelThresh
15723 clickPixelThresh: 3,
15726 * The number of milliseconds after the mousedown event to initiate the
15727 * drag if we don't get a mouseup event. Default=1000
15728 * @property clickTimeThresh
15732 clickTimeThresh: 350,
15735 * Flag that indicates that either the drag pixel threshold or the
15736 * mousdown time threshold has been met
15737 * @property dragThreshMet
15742 dragThreshMet: false,
15745 * Timeout used for the click time threshold
15746 * @property clickTimeout
15751 clickTimeout: null,
15754 * The X position of the mousedown event stored for later use when a
15755 * drag threshold is met.
15764 * The Y position of the mousedown event stored for later use when a
15765 * drag threshold is met.
15774 * Each DragDrop instance must be registered with the DragDropMgr.
15775 * This is executed in DragDrop.init()
15776 * @method regDragDrop
15777 * @param {DragDrop} oDD the DragDrop object to register
15778 * @param {String} sGroup the name of the group this element belongs to
15781 regDragDrop: function(oDD, sGroup) {
15782 if (!this.initialized) { this.init(); }
15784 if (!this.ids[sGroup]) {
15785 this.ids[sGroup] = {};
15787 this.ids[sGroup][oDD.id] = oDD;
15791 * Removes the supplied dd instance from the supplied group. Executed
15792 * by DragDrop.removeFromGroup, so don't call this function directly.
15793 * @method removeDDFromGroup
15797 removeDDFromGroup: function(oDD, sGroup) {
15798 if (!this.ids[sGroup]) {
15799 this.ids[sGroup] = {};
15802 var obj = this.ids[sGroup];
15803 if (obj && obj[oDD.id]) {
15804 delete obj[oDD.id];
15809 * Unregisters a drag and drop item. This is executed in
15810 * DragDrop.unreg, use that method instead of calling this directly.
15815 _remove: function(oDD) {
15816 for (var g in oDD.groups) {
15817 if (g && this.ids[g][oDD.id]) {
15818 delete this.ids[g][oDD.id];
15821 delete this.handleIds[oDD.id];
15825 * Each DragDrop handle element must be registered. This is done
15826 * automatically when executing DragDrop.setHandleElId()
15827 * @method regHandle
15828 * @param {String} sDDId the DragDrop id this element is a handle for
15829 * @param {String} sHandleId the id of the element that is the drag
15833 regHandle: function(sDDId, sHandleId) {
15834 if (!this.handleIds[sDDId]) {
15835 this.handleIds[sDDId] = {};
15837 this.handleIds[sDDId][sHandleId] = sHandleId;
15841 * Utility function to determine if a given element has been
15842 * registered as a drag drop item.
15843 * @method isDragDrop
15844 * @param {String} id the element id to check
15845 * @return {boolean} true if this element is a DragDrop item,
15849 isDragDrop: function(id) {
15850 return ( this.getDDById(id) ) ? true : false;
15854 * Returns the drag and drop instances that are in all groups the
15855 * passed in instance belongs to.
15856 * @method getRelated
15857 * @param {DragDrop} p_oDD the obj to get related data for
15858 * @param {boolean} bTargetsOnly if true, only return targetable objs
15859 * @return {DragDrop[]} the related instances
15862 getRelated: function(p_oDD, bTargetsOnly) {
15864 for (var i in p_oDD.groups) {
15865 for (j in this.ids[i]) {
15866 var dd = this.ids[i][j];
15867 if (! this.isTypeOfDD(dd)) {
15870 if (!bTargetsOnly || dd.isTarget) {
15871 oDDs[oDDs.length] = dd;
15880 * Returns true if the specified dd target is a legal target for
15881 * the specifice drag obj
15882 * @method isLegalTarget
15883 * @param {DragDrop} the drag obj
15884 * @param {DragDrop} the target
15885 * @return {boolean} true if the target is a legal target for the
15889 isLegalTarget: function (oDD, oTargetDD) {
15890 var targets = this.getRelated(oDD, true);
15891 for (var i=0, len=targets.length;i<len;++i) {
15892 if (targets[i].id == oTargetDD.id) {
15901 * My goal is to be able to transparently determine if an object is
15902 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15903 * returns "object", oDD.constructor.toString() always returns
15904 * "DragDrop" and not the name of the subclass. So for now it just
15905 * evaluates a well-known variable in DragDrop.
15906 * @method isTypeOfDD
15907 * @param {Object} the object to evaluate
15908 * @return {boolean} true if typeof oDD = DragDrop
15911 isTypeOfDD: function (oDD) {
15912 return (oDD && oDD.__ygDragDrop);
15916 * Utility function to determine if a given element has been
15917 * registered as a drag drop handle for the given Drag Drop object.
15919 * @param {String} id the element id to check
15920 * @return {boolean} true if this element is a DragDrop handle, false
15924 isHandle: function(sDDId, sHandleId) {
15925 return ( this.handleIds[sDDId] &&
15926 this.handleIds[sDDId][sHandleId] );
15930 * Returns the DragDrop instance for a given id
15931 * @method getDDById
15932 * @param {String} id the id of the DragDrop object
15933 * @return {DragDrop} the drag drop object, null if it is not found
15936 getDDById: function(id) {
15937 for (var i in this.ids) {
15938 if (this.ids[i][id]) {
15939 return this.ids[i][id];
15946 * Fired after a registered DragDrop object gets the mousedown event.
15947 * Sets up the events required to track the object being dragged
15948 * @method handleMouseDown
15949 * @param {Event} e the event
15950 * @param oDD the DragDrop object being dragged
15954 handleMouseDown: function(e, oDD) {
15956 Roo.QuickTips.disable();
15958 this.currentTarget = e.getTarget();
15960 this.dragCurrent = oDD;
15962 var el = oDD.getEl();
15964 // track start position
15965 this.startX = e.getPageX();
15966 this.startY = e.getPageY();
15968 this.deltaX = this.startX - el.offsetLeft;
15969 this.deltaY = this.startY - el.offsetTop;
15971 this.dragThreshMet = false;
15973 this.clickTimeout = setTimeout(
15975 var DDM = Roo.dd.DDM;
15976 DDM.startDrag(DDM.startX, DDM.startY);
15978 this.clickTimeThresh );
15982 * Fired when either the drag pixel threshol or the mousedown hold
15983 * time threshold has been met.
15984 * @method startDrag
15985 * @param x {int} the X position of the original mousedown
15986 * @param y {int} the Y position of the original mousedown
15989 startDrag: function(x, y) {
15990 clearTimeout(this.clickTimeout);
15991 if (this.dragCurrent) {
15992 this.dragCurrent.b4StartDrag(x, y);
15993 this.dragCurrent.startDrag(x, y);
15995 this.dragThreshMet = true;
15999 * Internal function to handle the mouseup event. Will be invoked
16000 * from the context of the document.
16001 * @method handleMouseUp
16002 * @param {Event} e the event
16006 handleMouseUp: function(e) {
16009 Roo.QuickTips.enable();
16011 if (! this.dragCurrent) {
16015 clearTimeout(this.clickTimeout);
16017 if (this.dragThreshMet) {
16018 this.fireEvents(e, true);
16028 * Utility to stop event propagation and event default, if these
16029 * features are turned on.
16030 * @method stopEvent
16031 * @param {Event} e the event as returned by this.getEvent()
16034 stopEvent: function(e){
16035 if(this.stopPropagation) {
16036 e.stopPropagation();
16039 if (this.preventDefault) {
16040 e.preventDefault();
16045 * Internal function to clean up event handlers after the drag
16046 * operation is complete
16048 * @param {Event} e the event
16052 stopDrag: function(e) {
16053 // Fire the drag end event for the item that was dragged
16054 if (this.dragCurrent) {
16055 if (this.dragThreshMet) {
16056 this.dragCurrent.b4EndDrag(e);
16057 this.dragCurrent.endDrag(e);
16060 this.dragCurrent.onMouseUp(e);
16063 this.dragCurrent = null;
16064 this.dragOvers = {};
16068 * Internal function to handle the mousemove event. Will be invoked
16069 * from the context of the html element.
16071 * @TODO figure out what we can do about mouse events lost when the
16072 * user drags objects beyond the window boundary. Currently we can
16073 * detect this in internet explorer by verifying that the mouse is
16074 * down during the mousemove event. Firefox doesn't give us the
16075 * button state on the mousemove event.
16076 * @method handleMouseMove
16077 * @param {Event} e the event
16081 handleMouseMove: function(e) {
16082 if (! this.dragCurrent) {
16086 // var button = e.which || e.button;
16088 // check for IE mouseup outside of page boundary
16089 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16091 return this.handleMouseUp(e);
16094 if (!this.dragThreshMet) {
16095 var diffX = Math.abs(this.startX - e.getPageX());
16096 var diffY = Math.abs(this.startY - e.getPageY());
16097 if (diffX > this.clickPixelThresh ||
16098 diffY > this.clickPixelThresh) {
16099 this.startDrag(this.startX, this.startY);
16103 if (this.dragThreshMet) {
16104 this.dragCurrent.b4Drag(e);
16105 this.dragCurrent.onDrag(e);
16106 if(!this.dragCurrent.moveOnly){
16107 this.fireEvents(e, false);
16117 * Iterates over all of the DragDrop elements to find ones we are
16118 * hovering over or dropping on
16119 * @method fireEvents
16120 * @param {Event} e the event
16121 * @param {boolean} isDrop is this a drop op or a mouseover op?
16125 fireEvents: function(e, isDrop) {
16126 var dc = this.dragCurrent;
16128 // If the user did the mouse up outside of the window, we could
16129 // get here even though we have ended the drag.
16130 if (!dc || dc.isLocked()) {
16134 var pt = e.getPoint();
16136 // cache the previous dragOver array
16142 var enterEvts = [];
16144 // Check to see if the object(s) we were hovering over is no longer
16145 // being hovered over so we can fire the onDragOut event
16146 for (var i in this.dragOvers) {
16148 var ddo = this.dragOvers[i];
16150 if (! this.isTypeOfDD(ddo)) {
16154 if (! this.isOverTarget(pt, ddo, this.mode)) {
16155 outEvts.push( ddo );
16158 oldOvers[i] = true;
16159 delete this.dragOvers[i];
16162 for (var sGroup in dc.groups) {
16164 if ("string" != typeof sGroup) {
16168 for (i in this.ids[sGroup]) {
16169 var oDD = this.ids[sGroup][i];
16170 if (! this.isTypeOfDD(oDD)) {
16174 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16175 if (this.isOverTarget(pt, oDD, this.mode)) {
16176 // look for drop interactions
16178 dropEvts.push( oDD );
16179 // look for drag enter and drag over interactions
16182 // initial drag over: dragEnter fires
16183 if (!oldOvers[oDD.id]) {
16184 enterEvts.push( oDD );
16185 // subsequent drag overs: dragOver fires
16187 overEvts.push( oDD );
16190 this.dragOvers[oDD.id] = oDD;
16198 if (outEvts.length) {
16199 dc.b4DragOut(e, outEvts);
16200 dc.onDragOut(e, outEvts);
16203 if (enterEvts.length) {
16204 dc.onDragEnter(e, enterEvts);
16207 if (overEvts.length) {
16208 dc.b4DragOver(e, overEvts);
16209 dc.onDragOver(e, overEvts);
16212 if (dropEvts.length) {
16213 dc.b4DragDrop(e, dropEvts);
16214 dc.onDragDrop(e, dropEvts);
16218 // fire dragout events
16220 for (i=0, len=outEvts.length; i<len; ++i) {
16221 dc.b4DragOut(e, outEvts[i].id);
16222 dc.onDragOut(e, outEvts[i].id);
16225 // fire enter events
16226 for (i=0,len=enterEvts.length; i<len; ++i) {
16227 // dc.b4DragEnter(e, oDD.id);
16228 dc.onDragEnter(e, enterEvts[i].id);
16231 // fire over events
16232 for (i=0,len=overEvts.length; i<len; ++i) {
16233 dc.b4DragOver(e, overEvts[i].id);
16234 dc.onDragOver(e, overEvts[i].id);
16237 // fire drop events
16238 for (i=0, len=dropEvts.length; i<len; ++i) {
16239 dc.b4DragDrop(e, dropEvts[i].id);
16240 dc.onDragDrop(e, dropEvts[i].id);
16245 // notify about a drop that did not find a target
16246 if (isDrop && !dropEvts.length) {
16247 dc.onInvalidDrop(e);
16253 * Helper function for getting the best match from the list of drag
16254 * and drop objects returned by the drag and drop events when we are
16255 * in INTERSECT mode. It returns either the first object that the
16256 * cursor is over, or the object that has the greatest overlap with
16257 * the dragged element.
16258 * @method getBestMatch
16259 * @param {DragDrop[]} dds The array of drag and drop objects
16261 * @return {DragDrop} The best single match
16264 getBestMatch: function(dds) {
16266 // Return null if the input is not what we expect
16267 //if (!dds || !dds.length || dds.length == 0) {
16269 // If there is only one item, it wins
16270 //} else if (dds.length == 1) {
16272 var len = dds.length;
16277 // Loop through the targeted items
16278 for (var i=0; i<len; ++i) {
16280 // If the cursor is over the object, it wins. If the
16281 // cursor is over multiple matches, the first one we come
16283 if (dd.cursorIsOver) {
16286 // Otherwise the object with the most overlap wins
16289 winner.overlap.getArea() < dd.overlap.getArea()) {
16300 * Refreshes the cache of the top-left and bottom-right points of the
16301 * drag and drop objects in the specified group(s). This is in the
16302 * format that is stored in the drag and drop instance, so typical
16305 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16309 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16311 * @TODO this really should be an indexed array. Alternatively this
16312 * method could accept both.
16313 * @method refreshCache
16314 * @param {Object} groups an associative array of groups to refresh
16317 refreshCache: function(groups) {
16318 for (var sGroup in groups) {
16319 if ("string" != typeof sGroup) {
16322 for (var i in this.ids[sGroup]) {
16323 var oDD = this.ids[sGroup][i];
16325 if (this.isTypeOfDD(oDD)) {
16326 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16327 var loc = this.getLocation(oDD);
16329 this.locationCache[oDD.id] = loc;
16331 delete this.locationCache[oDD.id];
16332 // this will unregister the drag and drop object if
16333 // the element is not in a usable state
16342 * This checks to make sure an element exists and is in the DOM. The
16343 * main purpose is to handle cases where innerHTML is used to remove
16344 * drag and drop objects from the DOM. IE provides an 'unspecified
16345 * error' when trying to access the offsetParent of such an element
16347 * @param {HTMLElement} el the element to check
16348 * @return {boolean} true if the element looks usable
16351 verifyEl: function(el) {
16356 parent = el.offsetParent;
16359 parent = el.offsetParent;
16370 * Returns a Region object containing the drag and drop element's position
16371 * and size, including the padding configured for it
16372 * @method getLocation
16373 * @param {DragDrop} oDD the drag and drop object to get the
16375 * @return {Roo.lib.Region} a Region object representing the total area
16376 * the element occupies, including any padding
16377 * the instance is configured for.
16380 getLocation: function(oDD) {
16381 if (! this.isTypeOfDD(oDD)) {
16385 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16388 pos= Roo.lib.Dom.getXY(el);
16396 x2 = x1 + el.offsetWidth;
16398 y2 = y1 + el.offsetHeight;
16400 t = y1 - oDD.padding[0];
16401 r = x2 + oDD.padding[1];
16402 b = y2 + oDD.padding[2];
16403 l = x1 - oDD.padding[3];
16405 return new Roo.lib.Region( t, r, b, l );
16409 * Checks the cursor location to see if it over the target
16410 * @method isOverTarget
16411 * @param {Roo.lib.Point} pt The point to evaluate
16412 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16413 * @return {boolean} true if the mouse is over the target
16417 isOverTarget: function(pt, oTarget, intersect) {
16418 // use cache if available
16419 var loc = this.locationCache[oTarget.id];
16420 if (!loc || !this.useCache) {
16421 loc = this.getLocation(oTarget);
16422 this.locationCache[oTarget.id] = loc;
16430 oTarget.cursorIsOver = loc.contains( pt );
16432 // DragDrop is using this as a sanity check for the initial mousedown
16433 // in this case we are done. In POINT mode, if the drag obj has no
16434 // contraints, we are also done. Otherwise we need to evaluate the
16435 // location of the target as related to the actual location of the
16436 // dragged element.
16437 var dc = this.dragCurrent;
16438 if (!dc || !dc.getTargetCoord ||
16439 (!intersect && !dc.constrainX && !dc.constrainY)) {
16440 return oTarget.cursorIsOver;
16443 oTarget.overlap = null;
16445 // Get the current location of the drag element, this is the
16446 // location of the mouse event less the delta that represents
16447 // where the original mousedown happened on the element. We
16448 // need to consider constraints and ticks as well.
16449 var pos = dc.getTargetCoord(pt.x, pt.y);
16451 var el = dc.getDragEl();
16452 var curRegion = new Roo.lib.Region( pos.y,
16453 pos.x + el.offsetWidth,
16454 pos.y + el.offsetHeight,
16457 var overlap = curRegion.intersect(loc);
16460 oTarget.overlap = overlap;
16461 return (intersect) ? true : oTarget.cursorIsOver;
16468 * unload event handler
16469 * @method _onUnload
16473 _onUnload: function(e, me) {
16474 Roo.dd.DragDropMgr.unregAll();
16478 * Cleans up the drag and drop events and objects.
16483 unregAll: function() {
16485 if (this.dragCurrent) {
16487 this.dragCurrent = null;
16490 this._execOnAll("unreg", []);
16492 for (i in this.elementCache) {
16493 delete this.elementCache[i];
16496 this.elementCache = {};
16501 * A cache of DOM elements
16502 * @property elementCache
16509 * Get the wrapper for the DOM element specified
16510 * @method getElWrapper
16511 * @param {String} id the id of the element to get
16512 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16514 * @deprecated This wrapper isn't that useful
16517 getElWrapper: function(id) {
16518 var oWrapper = this.elementCache[id];
16519 if (!oWrapper || !oWrapper.el) {
16520 oWrapper = this.elementCache[id] =
16521 new this.ElementWrapper(Roo.getDom(id));
16527 * Returns the actual DOM element
16528 * @method getElement
16529 * @param {String} id the id of the elment to get
16530 * @return {Object} The element
16531 * @deprecated use Roo.getDom instead
16534 getElement: function(id) {
16535 return Roo.getDom(id);
16539 * Returns the style property for the DOM element (i.e.,
16540 * document.getElById(id).style)
16542 * @param {String} id the id of the elment to get
16543 * @return {Object} The style property of the element
16544 * @deprecated use Roo.getDom instead
16547 getCss: function(id) {
16548 var el = Roo.getDom(id);
16549 return (el) ? el.style : null;
16553 * Inner class for cached elements
16554 * @class DragDropMgr.ElementWrapper
16559 ElementWrapper: function(el) {
16564 this.el = el || null;
16569 this.id = this.el && el.id;
16571 * A reference to the style property
16574 this.css = this.el && el.style;
16578 * Returns the X position of an html element
16580 * @param el the element for which to get the position
16581 * @return {int} the X coordinate
16583 * @deprecated use Roo.lib.Dom.getX instead
16586 getPosX: function(el) {
16587 return Roo.lib.Dom.getX(el);
16591 * Returns the Y position of an html element
16593 * @param el the element for which to get the position
16594 * @return {int} the Y coordinate
16595 * @deprecated use Roo.lib.Dom.getY instead
16598 getPosY: function(el) {
16599 return Roo.lib.Dom.getY(el);
16603 * Swap two nodes. In IE, we use the native method, for others we
16604 * emulate the IE behavior
16606 * @param n1 the first node to swap
16607 * @param n2 the other node to swap
16610 swapNode: function(n1, n2) {
16614 var p = n2.parentNode;
16615 var s = n2.nextSibling;
16618 p.insertBefore(n1, n2);
16619 } else if (n2 == n1.nextSibling) {
16620 p.insertBefore(n2, n1);
16622 n1.parentNode.replaceChild(n2, n1);
16623 p.insertBefore(n1, s);
16629 * Returns the current scroll position
16630 * @method getScroll
16634 getScroll: function () {
16635 var t, l, dde=document.documentElement, db=document.body;
16636 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16638 l = dde.scrollLeft;
16645 return { top: t, left: l };
16649 * Returns the specified element style property
16651 * @param {HTMLElement} el the element
16652 * @param {string} styleProp the style property
16653 * @return {string} The value of the style property
16654 * @deprecated use Roo.lib.Dom.getStyle
16657 getStyle: function(el, styleProp) {
16658 return Roo.fly(el).getStyle(styleProp);
16662 * Gets the scrollTop
16663 * @method getScrollTop
16664 * @return {int} the document's scrollTop
16667 getScrollTop: function () { return this.getScroll().top; },
16670 * Gets the scrollLeft
16671 * @method getScrollLeft
16672 * @return {int} the document's scrollTop
16675 getScrollLeft: function () { return this.getScroll().left; },
16678 * Sets the x/y position of an element to the location of the
16681 * @param {HTMLElement} moveEl The element to move
16682 * @param {HTMLElement} targetEl The position reference element
16685 moveToEl: function (moveEl, targetEl) {
16686 var aCoord = Roo.lib.Dom.getXY(targetEl);
16687 Roo.lib.Dom.setXY(moveEl, aCoord);
16691 * Numeric array sort function
16692 * @method numericSort
16695 numericSort: function(a, b) { return (a - b); },
16699 * @property _timeoutCount
16706 * Trying to make the load order less important. Without this we get
16707 * an error if this file is loaded before the Event Utility.
16708 * @method _addListeners
16712 _addListeners: function() {
16713 var DDM = Roo.dd.DDM;
16714 if ( Roo.lib.Event && document ) {
16717 if (DDM._timeoutCount > 2000) {
16719 setTimeout(DDM._addListeners, 10);
16720 if (document && document.body) {
16721 DDM._timeoutCount += 1;
16728 * Recursively searches the immediate parent and all child nodes for
16729 * the handle element in order to determine wheter or not it was
16731 * @method handleWasClicked
16732 * @param node the html element to inspect
16735 handleWasClicked: function(node, id) {
16736 if (this.isHandle(id, node.id)) {
16739 // check to see if this is a text node child of the one we want
16740 var p = node.parentNode;
16743 if (this.isHandle(id, p.id)) {
16758 // shorter alias, save a few bytes
16759 Roo.dd.DDM = Roo.dd.DragDropMgr;
16760 Roo.dd.DDM._addListeners();
16764 * Ext JS Library 1.1.1
16765 * Copyright(c) 2006-2007, Ext JS, LLC.
16767 * Originally Released Under LGPL - original licence link has changed is not relivant.
16770 * <script type="text/javascript">
16775 * A DragDrop implementation where the linked element follows the
16776 * mouse cursor during a drag.
16777 * @extends Roo.dd.DragDrop
16779 * @param {String} id the id of the linked element
16780 * @param {String} sGroup the group of related DragDrop items
16781 * @param {object} config an object containing configurable attributes
16782 * Valid properties for DD:
16785 Roo.dd.DD = function(id, sGroup, config) {
16787 this.init(id, sGroup, config);
16791 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16794 * When set to true, the utility automatically tries to scroll the browser
16795 * window wehn a drag and drop element is dragged near the viewport boundary.
16796 * Defaults to true.
16803 * Sets the pointer offset to the distance between the linked element's top
16804 * left corner and the location the element was clicked
16805 * @method autoOffset
16806 * @param {int} iPageX the X coordinate of the click
16807 * @param {int} iPageY the Y coordinate of the click
16809 autoOffset: function(iPageX, iPageY) {
16810 var x = iPageX - this.startPageX;
16811 var y = iPageY - this.startPageY;
16812 this.setDelta(x, y);
16816 * Sets the pointer offset. You can call this directly to force the
16817 * offset to be in a particular location (e.g., pass in 0,0 to set it
16818 * to the center of the object)
16820 * @param {int} iDeltaX the distance from the left
16821 * @param {int} iDeltaY the distance from the top
16823 setDelta: function(iDeltaX, iDeltaY) {
16824 this.deltaX = iDeltaX;
16825 this.deltaY = iDeltaY;
16829 * Sets the drag element to the location of the mousedown or click event,
16830 * maintaining the cursor location relative to the location on the element
16831 * that was clicked. Override this if you want to place the element in a
16832 * location other than where the cursor is.
16833 * @method setDragElPos
16834 * @param {int} iPageX the X coordinate of the mousedown or drag event
16835 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16837 setDragElPos: function(iPageX, iPageY) {
16838 // the first time we do this, we are going to check to make sure
16839 // the element has css positioning
16841 var el = this.getDragEl();
16842 this.alignElWithMouse(el, iPageX, iPageY);
16846 * Sets the element to the location of the mousedown or click event,
16847 * maintaining the cursor location relative to the location on the element
16848 * that was clicked. Override this if you want to place the element in a
16849 * location other than where the cursor is.
16850 * @method alignElWithMouse
16851 * @param {HTMLElement} el the element to move
16852 * @param {int} iPageX the X coordinate of the mousedown or drag event
16853 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16855 alignElWithMouse: function(el, iPageX, iPageY) {
16856 var oCoord = this.getTargetCoord(iPageX, iPageY);
16857 var fly = el.dom ? el : Roo.fly(el);
16858 if (!this.deltaSetXY) {
16859 var aCoord = [oCoord.x, oCoord.y];
16861 var newLeft = fly.getLeft(true);
16862 var newTop = fly.getTop(true);
16863 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16865 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16868 this.cachePosition(oCoord.x, oCoord.y);
16869 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16874 * Saves the most recent position so that we can reset the constraints and
16875 * tick marks on-demand. We need to know this so that we can calculate the
16876 * number of pixels the element is offset from its original position.
16877 * @method cachePosition
16878 * @param iPageX the current x position (optional, this just makes it so we
16879 * don't have to look it up again)
16880 * @param iPageY the current y position (optional, this just makes it so we
16881 * don't have to look it up again)
16883 cachePosition: function(iPageX, iPageY) {
16885 this.lastPageX = iPageX;
16886 this.lastPageY = iPageY;
16888 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16889 this.lastPageX = aCoord[0];
16890 this.lastPageY = aCoord[1];
16895 * Auto-scroll the window if the dragged object has been moved beyond the
16896 * visible window boundary.
16897 * @method autoScroll
16898 * @param {int} x the drag element's x position
16899 * @param {int} y the drag element's y position
16900 * @param {int} h the height of the drag element
16901 * @param {int} w the width of the drag element
16904 autoScroll: function(x, y, h, w) {
16907 // The client height
16908 var clientH = Roo.lib.Dom.getViewWidth();
16910 // The client width
16911 var clientW = Roo.lib.Dom.getViewHeight();
16913 // The amt scrolled down
16914 var st = this.DDM.getScrollTop();
16916 // The amt scrolled right
16917 var sl = this.DDM.getScrollLeft();
16919 // Location of the bottom of the element
16922 // Location of the right of the element
16925 // The distance from the cursor to the bottom of the visible area,
16926 // adjusted so that we don't scroll if the cursor is beyond the
16927 // element drag constraints
16928 var toBot = (clientH + st - y - this.deltaY);
16930 // The distance from the cursor to the right of the visible area
16931 var toRight = (clientW + sl - x - this.deltaX);
16934 // How close to the edge the cursor must be before we scroll
16935 // var thresh = (document.all) ? 100 : 40;
16938 // How many pixels to scroll per autoscroll op. This helps to reduce
16939 // clunky scrolling. IE is more sensitive about this ... it needs this
16940 // value to be higher.
16941 var scrAmt = (document.all) ? 80 : 30;
16943 // Scroll down if we are near the bottom of the visible page and the
16944 // obj extends below the crease
16945 if ( bot > clientH && toBot < thresh ) {
16946 window.scrollTo(sl, st + scrAmt);
16949 // Scroll up if the window is scrolled down and the top of the object
16950 // goes above the top border
16951 if ( y < st && st > 0 && y - st < thresh ) {
16952 window.scrollTo(sl, st - scrAmt);
16955 // Scroll right if the obj is beyond the right border and the cursor is
16956 // near the border.
16957 if ( right > clientW && toRight < thresh ) {
16958 window.scrollTo(sl + scrAmt, st);
16961 // Scroll left if the window has been scrolled to the right and the obj
16962 // extends past the left border
16963 if ( x < sl && sl > 0 && x - sl < thresh ) {
16964 window.scrollTo(sl - scrAmt, st);
16970 * Finds the location the element should be placed if we want to move
16971 * it to where the mouse location less the click offset would place us.
16972 * @method getTargetCoord
16973 * @param {int} iPageX the X coordinate of the click
16974 * @param {int} iPageY the Y coordinate of the click
16975 * @return an object that contains the coordinates (Object.x and Object.y)
16978 getTargetCoord: function(iPageX, iPageY) {
16981 var x = iPageX - this.deltaX;
16982 var y = iPageY - this.deltaY;
16984 if (this.constrainX) {
16985 if (x < this.minX) { x = this.minX; }
16986 if (x > this.maxX) { x = this.maxX; }
16989 if (this.constrainY) {
16990 if (y < this.minY) { y = this.minY; }
16991 if (y > this.maxY) { y = this.maxY; }
16994 x = this.getTick(x, this.xTicks);
16995 y = this.getTick(y, this.yTicks);
17002 * Sets up config options specific to this class. Overrides
17003 * Roo.dd.DragDrop, but all versions of this method through the
17004 * inheritance chain are called
17006 applyConfig: function() {
17007 Roo.dd.DD.superclass.applyConfig.call(this);
17008 this.scroll = (this.config.scroll !== false);
17012 * Event that fires prior to the onMouseDown event. Overrides
17015 b4MouseDown: function(e) {
17016 // this.resetConstraints();
17017 this.autoOffset(e.getPageX(),
17022 * Event that fires prior to the onDrag event. Overrides
17025 b4Drag: function(e) {
17026 this.setDragElPos(e.getPageX(),
17030 toString: function() {
17031 return ("DD " + this.id);
17034 //////////////////////////////////////////////////////////////////////////
17035 // Debugging ygDragDrop events that can be overridden
17036 //////////////////////////////////////////////////////////////////////////
17038 startDrag: function(x, y) {
17041 onDrag: function(e) {
17044 onDragEnter: function(e, id) {
17047 onDragOver: function(e, id) {
17050 onDragOut: function(e, id) {
17053 onDragDrop: function(e, id) {
17056 endDrag: function(e) {
17063 * Ext JS Library 1.1.1
17064 * Copyright(c) 2006-2007, Ext JS, LLC.
17066 * Originally Released Under LGPL - original licence link has changed is not relivant.
17069 * <script type="text/javascript">
17073 * @class Roo.dd.DDProxy
17074 * A DragDrop implementation that inserts an empty, bordered div into
17075 * the document that follows the cursor during drag operations. At the time of
17076 * the click, the frame div is resized to the dimensions of the linked html
17077 * element, and moved to the exact location of the linked element.
17079 * References to the "frame" element refer to the single proxy element that
17080 * was created to be dragged in place of all DDProxy elements on the
17083 * @extends Roo.dd.DD
17085 * @param {String} id the id of the linked html element
17086 * @param {String} sGroup the group of related DragDrop objects
17087 * @param {object} config an object containing configurable attributes
17088 * Valid properties for DDProxy in addition to those in DragDrop:
17089 * resizeFrame, centerFrame, dragElId
17091 Roo.dd.DDProxy = function(id, sGroup, config) {
17093 this.init(id, sGroup, config);
17099 * The default drag frame div id
17100 * @property Roo.dd.DDProxy.dragElId
17104 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17106 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17109 * By default we resize the drag frame to be the same size as the element
17110 * we want to drag (this is to get the frame effect). We can turn it off
17111 * if we want a different behavior.
17112 * @property resizeFrame
17118 * By default the frame is positioned exactly where the drag element is, so
17119 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17120 * you do not have constraints on the obj is to have the drag frame centered
17121 * around the cursor. Set centerFrame to true for this effect.
17122 * @property centerFrame
17125 centerFrame: false,
17128 * Creates the proxy element if it does not yet exist
17129 * @method createFrame
17131 createFrame: function() {
17133 var body = document.body;
17135 if (!body || !body.firstChild) {
17136 setTimeout( function() { self.createFrame(); }, 50 );
17140 var div = this.getDragEl();
17143 div = document.createElement("div");
17144 div.id = this.dragElId;
17147 s.position = "absolute";
17148 s.visibility = "hidden";
17150 s.border = "2px solid #aaa";
17153 // appendChild can blow up IE if invoked prior to the window load event
17154 // while rendering a table. It is possible there are other scenarios
17155 // that would cause this to happen as well.
17156 body.insertBefore(div, body.firstChild);
17161 * Initialization for the drag frame element. Must be called in the
17162 * constructor of all subclasses
17163 * @method initFrame
17165 initFrame: function() {
17166 this.createFrame();
17169 applyConfig: function() {
17170 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17172 this.resizeFrame = (this.config.resizeFrame !== false);
17173 this.centerFrame = (this.config.centerFrame);
17174 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17178 * Resizes the drag frame to the dimensions of the clicked object, positions
17179 * it over the object, and finally displays it
17180 * @method showFrame
17181 * @param {int} iPageX X click position
17182 * @param {int} iPageY Y click position
17185 showFrame: function(iPageX, iPageY) {
17186 var el = this.getEl();
17187 var dragEl = this.getDragEl();
17188 var s = dragEl.style;
17190 this._resizeProxy();
17192 if (this.centerFrame) {
17193 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17194 Math.round(parseInt(s.height, 10)/2) );
17197 this.setDragElPos(iPageX, iPageY);
17199 Roo.fly(dragEl).show();
17203 * The proxy is automatically resized to the dimensions of the linked
17204 * element when a drag is initiated, unless resizeFrame is set to false
17205 * @method _resizeProxy
17208 _resizeProxy: function() {
17209 if (this.resizeFrame) {
17210 var el = this.getEl();
17211 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17215 // overrides Roo.dd.DragDrop
17216 b4MouseDown: function(e) {
17217 var x = e.getPageX();
17218 var y = e.getPageY();
17219 this.autoOffset(x, y);
17220 this.setDragElPos(x, y);
17223 // overrides Roo.dd.DragDrop
17224 b4StartDrag: function(x, y) {
17225 // show the drag frame
17226 this.showFrame(x, y);
17229 // overrides Roo.dd.DragDrop
17230 b4EndDrag: function(e) {
17231 Roo.fly(this.getDragEl()).hide();
17234 // overrides Roo.dd.DragDrop
17235 // By default we try to move the element to the last location of the frame.
17236 // This is so that the default behavior mirrors that of Roo.dd.DD.
17237 endDrag: function(e) {
17239 var lel = this.getEl();
17240 var del = this.getDragEl();
17242 // Show the drag frame briefly so we can get its position
17243 del.style.visibility = "";
17246 // Hide the linked element before the move to get around a Safari
17248 lel.style.visibility = "hidden";
17249 Roo.dd.DDM.moveToEl(lel, del);
17250 del.style.visibility = "hidden";
17251 lel.style.visibility = "";
17256 beforeMove : function(){
17260 afterDrag : function(){
17264 toString: function() {
17265 return ("DDProxy " + this.id);
17271 * Ext JS Library 1.1.1
17272 * Copyright(c) 2006-2007, Ext JS, LLC.
17274 * Originally Released Under LGPL - original licence link has changed is not relivant.
17277 * <script type="text/javascript">
17281 * @class Roo.dd.DDTarget
17282 * A DragDrop implementation that does not move, but can be a drop
17283 * target. You would get the same result by simply omitting implementation
17284 * for the event callbacks, but this way we reduce the processing cost of the
17285 * event listener and the callbacks.
17286 * @extends Roo.dd.DragDrop
17288 * @param {String} id the id of the element that is a drop target
17289 * @param {String} sGroup the group of related DragDrop objects
17290 * @param {object} config an object containing configurable attributes
17291 * Valid properties for DDTarget in addition to those in
17295 Roo.dd.DDTarget = function(id, sGroup, config) {
17297 this.initTarget(id, sGroup, config);
17301 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17302 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17303 toString: function() {
17304 return ("DDTarget " + this.id);
17309 * Ext JS Library 1.1.1
17310 * Copyright(c) 2006-2007, Ext JS, LLC.
17312 * Originally Released Under LGPL - original licence link has changed is not relivant.
17315 * <script type="text/javascript">
17320 * @class Roo.dd.ScrollManager
17321 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17322 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17325 Roo.dd.ScrollManager = function(){
17326 var ddm = Roo.dd.DragDropMgr;
17331 var onStop = function(e){
17336 var triggerRefresh = function(){
17337 if(ddm.dragCurrent){
17338 ddm.refreshCache(ddm.dragCurrent.groups);
17342 var doScroll = function(){
17343 if(ddm.dragCurrent){
17344 var dds = Roo.dd.ScrollManager;
17346 if(proc.el.scroll(proc.dir, dds.increment)){
17350 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17355 var clearProc = function(){
17357 clearInterval(proc.id);
17364 var startProc = function(el, dir){
17368 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17371 var onFire = function(e, isDrop){
17372 if(isDrop || !ddm.dragCurrent){ return; }
17373 var dds = Roo.dd.ScrollManager;
17374 if(!dragEl || dragEl != ddm.dragCurrent){
17375 dragEl = ddm.dragCurrent;
17376 // refresh regions on drag start
17377 dds.refreshCache();
17380 var xy = Roo.lib.Event.getXY(e);
17381 var pt = new Roo.lib.Point(xy[0], xy[1]);
17382 for(var id in els){
17383 var el = els[id], r = el._region;
17384 if(r && r.contains(pt) && el.isScrollable()){
17385 if(r.bottom - pt.y <= dds.thresh){
17387 startProc(el, "down");
17390 }else if(r.right - pt.x <= dds.thresh){
17392 startProc(el, "left");
17395 }else if(pt.y - r.top <= dds.thresh){
17397 startProc(el, "up");
17400 }else if(pt.x - r.left <= dds.thresh){
17402 startProc(el, "right");
17411 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17412 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17416 * Registers new overflow element(s) to auto scroll
17417 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17419 register : function(el){
17420 if(el instanceof Array){
17421 for(var i = 0, len = el.length; i < len; i++) {
17422 this.register(el[i]);
17431 * Unregisters overflow element(s) so they are no longer scrolled
17432 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17434 unregister : function(el){
17435 if(el instanceof Array){
17436 for(var i = 0, len = el.length; i < len; i++) {
17437 this.unregister(el[i]);
17446 * The number of pixels from the edge of a container the pointer needs to be to
17447 * trigger scrolling (defaults to 25)
17453 * The number of pixels to scroll in each scroll increment (defaults to 50)
17459 * The frequency of scrolls in milliseconds (defaults to 500)
17465 * True to animate the scroll (defaults to true)
17471 * The animation duration in seconds -
17472 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17478 * Manually trigger a cache refresh.
17480 refreshCache : function(){
17481 for(var id in els){
17482 if(typeof els[id] == 'object'){ // for people extending the object prototype
17483 els[id]._region = els[id].getRegion();
17490 * Ext JS Library 1.1.1
17491 * Copyright(c) 2006-2007, Ext JS, LLC.
17493 * Originally Released Under LGPL - original licence link has changed is not relivant.
17496 * <script type="text/javascript">
17501 * @class Roo.dd.Registry
17502 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17503 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17506 Roo.dd.Registry = function(){
17509 var autoIdSeed = 0;
17511 var getId = function(el, autogen){
17512 if(typeof el == "string"){
17516 if(!id && autogen !== false){
17517 id = "roodd-" + (++autoIdSeed);
17525 * Register a drag drop element
17526 * @param {String|HTMLElement} element The id or DOM node to register
17527 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17528 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17529 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17530 * populated in the data object (if applicable):
17532 Value Description<br />
17533 --------- ------------------------------------------<br />
17534 handles Array of DOM nodes that trigger dragging<br />
17535 for the element being registered<br />
17536 isHandle True if the element passed in triggers<br />
17537 dragging itself, else false
17540 register : function(el, data){
17542 if(typeof el == "string"){
17543 el = document.getElementById(el);
17546 elements[getId(el)] = data;
17547 if(data.isHandle !== false){
17548 handles[data.ddel.id] = data;
17551 var hs = data.handles;
17552 for(var i = 0, len = hs.length; i < len; i++){
17553 handles[getId(hs[i])] = data;
17559 * Unregister a drag drop element
17560 * @param {String|HTMLElement} element The id or DOM node to unregister
17562 unregister : function(el){
17563 var id = getId(el, false);
17564 var data = elements[id];
17566 delete elements[id];
17568 var hs = data.handles;
17569 for(var i = 0, len = hs.length; i < len; i++){
17570 delete handles[getId(hs[i], false)];
17577 * Returns the handle registered for a DOM Node by id
17578 * @param {String|HTMLElement} id The DOM node or id to look up
17579 * @return {Object} handle The custom handle data
17581 getHandle : function(id){
17582 if(typeof id != "string"){ // must be element?
17585 return handles[id];
17589 * Returns the handle that is registered for the DOM node that is the target of the event
17590 * @param {Event} e The event
17591 * @return {Object} handle The custom handle data
17593 getHandleFromEvent : function(e){
17594 var t = Roo.lib.Event.getTarget(e);
17595 return t ? handles[t.id] : null;
17599 * Returns a custom data object that is registered for a DOM node by id
17600 * @param {String|HTMLElement} id The DOM node or id to look up
17601 * @return {Object} data The custom data
17603 getTarget : function(id){
17604 if(typeof id != "string"){ // must be element?
17607 return elements[id];
17611 * Returns a custom data object that is registered for the DOM node that is the target of the event
17612 * @param {Event} e The event
17613 * @return {Object} data The custom data
17615 getTargetFromEvent : function(e){
17616 var t = Roo.lib.Event.getTarget(e);
17617 return t ? elements[t.id] || handles[t.id] : null;
17622 * Ext JS Library 1.1.1
17623 * Copyright(c) 2006-2007, Ext JS, LLC.
17625 * Originally Released Under LGPL - original licence link has changed is not relivant.
17628 * <script type="text/javascript">
17633 * @class Roo.dd.StatusProxy
17634 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17635 * default drag proxy used by all Roo.dd components.
17637 * @param {Object} config
17639 Roo.dd.StatusProxy = function(config){
17640 Roo.apply(this, config);
17641 this.id = this.id || Roo.id();
17642 this.el = new Roo.Layer({
17644 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17645 {tag: "div", cls: "x-dd-drop-icon"},
17646 {tag: "div", cls: "x-dd-drag-ghost"}
17649 shadow: !config || config.shadow !== false
17651 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17652 this.dropStatus = this.dropNotAllowed;
17655 Roo.dd.StatusProxy.prototype = {
17657 * @cfg {String} dropAllowed
17658 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17660 dropAllowed : "x-dd-drop-ok",
17662 * @cfg {String} dropNotAllowed
17663 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17665 dropNotAllowed : "x-dd-drop-nodrop",
17668 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17669 * over the current target element.
17670 * @param {String} cssClass The css class for the new drop status indicator image
17672 setStatus : function(cssClass){
17673 cssClass = cssClass || this.dropNotAllowed;
17674 if(this.dropStatus != cssClass){
17675 this.el.replaceClass(this.dropStatus, cssClass);
17676 this.dropStatus = cssClass;
17681 * Resets the status indicator to the default dropNotAllowed value
17682 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17684 reset : function(clearGhost){
17685 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17686 this.dropStatus = this.dropNotAllowed;
17688 this.ghost.update("");
17693 * Updates the contents of the ghost element
17694 * @param {String} html The html that will replace the current innerHTML of the ghost element
17696 update : function(html){
17697 if(typeof html == "string"){
17698 this.ghost.update(html);
17700 this.ghost.update("");
17701 html.style.margin = "0";
17702 this.ghost.dom.appendChild(html);
17704 // ensure float = none set?? cant remember why though.
17705 var el = this.ghost.dom.firstChild;
17707 Roo.fly(el).setStyle('float', 'none');
17712 * Returns the underlying proxy {@link Roo.Layer}
17713 * @return {Roo.Layer} el
17715 getEl : function(){
17720 * Returns the ghost element
17721 * @return {Roo.Element} el
17723 getGhost : function(){
17729 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17731 hide : function(clear){
17739 * Stops the repair animation if it's currently running
17742 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17748 * Displays this proxy
17755 * Force the Layer to sync its shadow and shim positions to the element
17762 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17763 * invalid drop operation by the item being dragged.
17764 * @param {Array} xy The XY position of the element ([x, y])
17765 * @param {Function} callback The function to call after the repair is complete
17766 * @param {Object} scope The scope in which to execute the callback
17768 repair : function(xy, callback, scope){
17769 this.callback = callback;
17770 this.scope = scope;
17771 if(xy && this.animRepair !== false){
17772 this.el.addClass("x-dd-drag-repair");
17773 this.el.hideUnders(true);
17774 this.anim = this.el.shift({
17775 duration: this.repairDuration || .5,
17779 callback: this.afterRepair,
17783 this.afterRepair();
17788 afterRepair : function(){
17790 if(typeof this.callback == "function"){
17791 this.callback.call(this.scope || this);
17793 this.callback = null;
17798 * Ext JS Library 1.1.1
17799 * Copyright(c) 2006-2007, Ext JS, LLC.
17801 * Originally Released Under LGPL - original licence link has changed is not relivant.
17804 * <script type="text/javascript">
17808 * @class Roo.dd.DragSource
17809 * @extends Roo.dd.DDProxy
17810 * A simple class that provides the basic implementation needed to make any element draggable.
17812 * @param {String/HTMLElement/Element} el The container element
17813 * @param {Object} config
17815 Roo.dd.DragSource = function(el, config){
17816 this.el = Roo.get(el);
17817 this.dragData = {};
17819 Roo.apply(this, config);
17822 this.proxy = new Roo.dd.StatusProxy();
17825 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17826 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17828 this.dragging = false;
17831 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17833 * @cfg {String} dropAllowed
17834 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17836 dropAllowed : "x-dd-drop-ok",
17838 * @cfg {String} dropNotAllowed
17839 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17841 dropNotAllowed : "x-dd-drop-nodrop",
17844 * Returns the data object associated with this drag source
17845 * @return {Object} data An object containing arbitrary data
17847 getDragData : function(e){
17848 return this.dragData;
17852 onDragEnter : function(e, id){
17853 var target = Roo.dd.DragDropMgr.getDDById(id);
17854 this.cachedTarget = target;
17855 if(this.beforeDragEnter(target, e, id) !== false){
17856 if(target.isNotifyTarget){
17857 var status = target.notifyEnter(this, e, this.dragData);
17858 this.proxy.setStatus(status);
17860 this.proxy.setStatus(this.dropAllowed);
17863 if(this.afterDragEnter){
17865 * An empty function by default, but provided so that you can perform a custom action
17866 * when the dragged item enters the drop target by providing an implementation.
17867 * @param {Roo.dd.DragDrop} target The drop target
17868 * @param {Event} e The event object
17869 * @param {String} id The id of the dragged element
17870 * @method afterDragEnter
17872 this.afterDragEnter(target, e, id);
17878 * An empty function by default, but provided so that you can perform a custom action
17879 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17880 * @param {Roo.dd.DragDrop} target The drop target
17881 * @param {Event} e The event object
17882 * @param {String} id The id of the dragged element
17883 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17885 beforeDragEnter : function(target, e, id){
17890 alignElWithMouse: function() {
17891 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17896 onDragOver : function(e, id){
17897 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17898 if(this.beforeDragOver(target, e, id) !== false){
17899 if(target.isNotifyTarget){
17900 var status = target.notifyOver(this, e, this.dragData);
17901 this.proxy.setStatus(status);
17904 if(this.afterDragOver){
17906 * An empty function by default, but provided so that you can perform a custom action
17907 * while the dragged item is over the drop target by providing an implementation.
17908 * @param {Roo.dd.DragDrop} target The drop target
17909 * @param {Event} e The event object
17910 * @param {String} id The id of the dragged element
17911 * @method afterDragOver
17913 this.afterDragOver(target, e, id);
17919 * An empty function by default, but provided so that you can perform a custom action
17920 * while the dragged item is over the drop target and optionally cancel the onDragOver.
17921 * @param {Roo.dd.DragDrop} target The drop target
17922 * @param {Event} e The event object
17923 * @param {String} id The id of the dragged element
17924 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17926 beforeDragOver : function(target, e, id){
17931 onDragOut : function(e, id){
17932 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17933 if(this.beforeDragOut(target, e, id) !== false){
17934 if(target.isNotifyTarget){
17935 target.notifyOut(this, e, this.dragData);
17937 this.proxy.reset();
17938 if(this.afterDragOut){
17940 * An empty function by default, but provided so that you can perform a custom action
17941 * after the dragged item is dragged out of the target without dropping.
17942 * @param {Roo.dd.DragDrop} target The drop target
17943 * @param {Event} e The event object
17944 * @param {String} id The id of the dragged element
17945 * @method afterDragOut
17947 this.afterDragOut(target, e, id);
17950 this.cachedTarget = null;
17954 * An empty function by default, but provided so that you can perform a custom action before the dragged
17955 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
17956 * @param {Roo.dd.DragDrop} target The drop target
17957 * @param {Event} e The event object
17958 * @param {String} id The id of the dragged element
17959 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17961 beforeDragOut : function(target, e, id){
17966 onDragDrop : function(e, id){
17967 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17968 if(this.beforeDragDrop(target, e, id) !== false){
17969 if(target.isNotifyTarget){
17970 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
17971 this.onValidDrop(target, e, id);
17973 this.onInvalidDrop(target, e, id);
17976 this.onValidDrop(target, e, id);
17979 if(this.afterDragDrop){
17981 * An empty function by default, but provided so that you can perform a custom action
17982 * after a valid drag drop has occurred by providing an implementation.
17983 * @param {Roo.dd.DragDrop} target The drop target
17984 * @param {Event} e The event object
17985 * @param {String} id The id of the dropped element
17986 * @method afterDragDrop
17988 this.afterDragDrop(target, e, id);
17991 delete this.cachedTarget;
17995 * An empty function by default, but provided so that you can perform a custom action before the dragged
17996 * item is dropped onto the target and optionally cancel the onDragDrop.
17997 * @param {Roo.dd.DragDrop} target The drop target
17998 * @param {Event} e The event object
17999 * @param {String} id The id of the dragged element
18000 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18002 beforeDragDrop : function(target, e, id){
18007 onValidDrop : function(target, e, id){
18009 if(this.afterValidDrop){
18011 * An empty function by default, but provided so that you can perform a custom action
18012 * after a valid drop has occurred by providing an implementation.
18013 * @param {Object} target The target DD
18014 * @param {Event} e The event object
18015 * @param {String} id The id of the dropped element
18016 * @method afterInvalidDrop
18018 this.afterValidDrop(target, e, id);
18023 getRepairXY : function(e, data){
18024 return this.el.getXY();
18028 onInvalidDrop : function(target, e, id){
18029 this.beforeInvalidDrop(target, e, id);
18030 if(this.cachedTarget){
18031 if(this.cachedTarget.isNotifyTarget){
18032 this.cachedTarget.notifyOut(this, e, this.dragData);
18034 this.cacheTarget = null;
18036 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18038 if(this.afterInvalidDrop){
18040 * An empty function by default, but provided so that you can perform a custom action
18041 * after an invalid drop has occurred by providing an implementation.
18042 * @param {Event} e The event object
18043 * @param {String} id The id of the dropped element
18044 * @method afterInvalidDrop
18046 this.afterInvalidDrop(e, id);
18051 afterRepair : function(){
18053 this.el.highlight(this.hlColor || "c3daf9");
18055 this.dragging = false;
18059 * An empty function by default, but provided so that you can perform a custom action after an invalid
18060 * drop has occurred.
18061 * @param {Roo.dd.DragDrop} target The drop target
18062 * @param {Event} e The event object
18063 * @param {String} id The id of the dragged element
18064 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18066 beforeInvalidDrop : function(target, e, id){
18071 handleMouseDown : function(e){
18072 if(this.dragging) {
18075 var data = this.getDragData(e);
18076 if(data && this.onBeforeDrag(data, e) !== false){
18077 this.dragData = data;
18079 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18084 * An empty function by default, but provided so that you can perform a custom action before the initial
18085 * drag event begins and optionally cancel it.
18086 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18087 * @param {Event} e The event object
18088 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18090 onBeforeDrag : function(data, e){
18095 * An empty function by default, but provided so that you can perform a custom action once the initial
18096 * drag event has begun. The drag cannot be canceled from this function.
18097 * @param {Number} x The x position of the click on the dragged object
18098 * @param {Number} y The y position of the click on the dragged object
18100 onStartDrag : Roo.emptyFn,
18102 // private - YUI override
18103 startDrag : function(x, y){
18104 this.proxy.reset();
18105 this.dragging = true;
18106 this.proxy.update("");
18107 this.onInitDrag(x, y);
18112 onInitDrag : function(x, y){
18113 var clone = this.el.dom.cloneNode(true);
18114 clone.id = Roo.id(); // prevent duplicate ids
18115 this.proxy.update(clone);
18116 this.onStartDrag(x, y);
18121 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18122 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18124 getProxy : function(){
18129 * Hides the drag source's {@link Roo.dd.StatusProxy}
18131 hideProxy : function(){
18133 this.proxy.reset(true);
18134 this.dragging = false;
18138 triggerCacheRefresh : function(){
18139 Roo.dd.DDM.refreshCache(this.groups);
18142 // private - override to prevent hiding
18143 b4EndDrag: function(e) {
18146 // private - override to prevent moving
18147 endDrag : function(e){
18148 this.onEndDrag(this.dragData, e);
18152 onEndDrag : function(data, e){
18155 // private - pin to cursor
18156 autoOffset : function(x, y) {
18157 this.setDelta(-12, -20);
18161 * Ext JS Library 1.1.1
18162 * Copyright(c) 2006-2007, Ext JS, LLC.
18164 * Originally Released Under LGPL - original licence link has changed is not relivant.
18167 * <script type="text/javascript">
18172 * @class Roo.dd.DropTarget
18173 * @extends Roo.dd.DDTarget
18174 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18175 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18177 * @param {String/HTMLElement/Element} el The container element
18178 * @param {Object} config
18180 Roo.dd.DropTarget = function(el, config){
18181 this.el = Roo.get(el);
18183 Roo.apply(this, config);
18185 if(this.containerScroll){
18186 Roo.dd.ScrollManager.register(this.el);
18189 Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18194 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18196 * @cfg {String} overClass
18197 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18200 * @cfg {String} dropAllowed
18201 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18203 dropAllowed : "x-dd-drop-ok",
18205 * @cfg {String} dropNotAllowed
18206 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18208 dropNotAllowed : "x-dd-drop-nodrop",
18214 isNotifyTarget : true,
18217 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18218 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18219 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18220 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18221 * @param {Event} e The event
18222 * @param {Object} data An object containing arbitrary data supplied by the drag source
18223 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18224 * underlying {@link Roo.dd.StatusProxy} can be updated
18226 notifyEnter : function(dd, e, data){
18227 if(this.overClass){
18228 this.el.addClass(this.overClass);
18230 return this.dropAllowed;
18234 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18235 * This method will be called on every mouse movement while the drag source is over the drop target.
18236 * This default implementation simply returns the dropAllowed config value.
18237 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18238 * @param {Event} e The event
18239 * @param {Object} data An object containing arbitrary data supplied by the drag source
18240 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18241 * underlying {@link Roo.dd.StatusProxy} can be updated
18243 notifyOver : function(dd, e, data){
18244 return this.dropAllowed;
18248 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18249 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18250 * overClass (if any) from the drop element.
18251 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18252 * @param {Event} e The event
18253 * @param {Object} data An object containing arbitrary data supplied by the drag source
18255 notifyOut : function(dd, e, data){
18256 if(this.overClass){
18257 this.el.removeClass(this.overClass);
18262 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18263 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18264 * implementation that does something to process the drop event and returns true so that the drag source's
18265 * repair action does not run.
18266 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18267 * @param {Event} e The event
18268 * @param {Object} data An object containing arbitrary data supplied by the drag source
18269 * @return {Boolean} True if the drop was valid, else false
18271 notifyDrop : function(dd, e, data){
18276 * Ext JS Library 1.1.1
18277 * Copyright(c) 2006-2007, Ext JS, LLC.
18279 * Originally Released Under LGPL - original licence link has changed is not relivant.
18282 * <script type="text/javascript">
18287 * @class Roo.dd.DragZone
18288 * @extends Roo.dd.DragSource
18289 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18290 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18292 * @param {String/HTMLElement/Element} el The container element
18293 * @param {Object} config
18295 Roo.dd.DragZone = function(el, config){
18296 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18297 if(this.containerScroll){
18298 Roo.dd.ScrollManager.register(this.el);
18302 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18304 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18305 * for auto scrolling during drag operations.
18308 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18309 * method after a failed drop (defaults to "c3daf9" - light blue)
18313 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18314 * for a valid target to drag based on the mouse down. Override this method
18315 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18316 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18317 * @param {EventObject} e The mouse down event
18318 * @return {Object} The dragData
18320 getDragData : function(e){
18321 return Roo.dd.Registry.getHandleFromEvent(e);
18325 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18326 * this.dragData.ddel
18327 * @param {Number} x The x position of the click on the dragged object
18328 * @param {Number} y The y position of the click on the dragged object
18329 * @return {Boolean} true to continue the drag, false to cancel
18331 onInitDrag : function(x, y){
18332 this.proxy.update(this.dragData.ddel.cloneNode(true));
18333 this.onStartDrag(x, y);
18338 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18340 afterRepair : function(){
18342 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18344 this.dragging = false;
18348 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18349 * the XY of this.dragData.ddel
18350 * @param {EventObject} e The mouse up event
18351 * @return {Array} The xy location (e.g. [100, 200])
18353 getRepairXY : function(e){
18354 return Roo.Element.fly(this.dragData.ddel).getXY();
18358 * Ext JS Library 1.1.1
18359 * Copyright(c) 2006-2007, Ext JS, LLC.
18361 * Originally Released Under LGPL - original licence link has changed is not relivant.
18364 * <script type="text/javascript">
18367 * @class Roo.dd.DropZone
18368 * @extends Roo.dd.DropTarget
18369 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18370 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18372 * @param {String/HTMLElement/Element} el The container element
18373 * @param {Object} config
18375 Roo.dd.DropZone = function(el, config){
18376 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18379 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18381 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18382 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18383 * provide your own custom lookup.
18384 * @param {Event} e The event
18385 * @return {Object} data The custom data
18387 getTargetFromEvent : function(e){
18388 return Roo.dd.Registry.getTargetFromEvent(e);
18392 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18393 * that it has registered. This method has no default implementation and should be overridden to provide
18394 * node-specific processing if necessary.
18395 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18396 * {@link #getTargetFromEvent} for this node)
18397 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18398 * @param {Event} e The event
18399 * @param {Object} data An object containing arbitrary data supplied by the drag source
18401 onNodeEnter : function(n, dd, e, data){
18406 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18407 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18408 * overridden to provide the proper feedback.
18409 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18410 * {@link #getTargetFromEvent} for this node)
18411 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18412 * @param {Event} e The event
18413 * @param {Object} data An object containing arbitrary data supplied by the drag source
18414 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18415 * underlying {@link Roo.dd.StatusProxy} can be updated
18417 onNodeOver : function(n, dd, e, data){
18418 return this.dropAllowed;
18422 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18423 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18424 * node-specific processing if necessary.
18425 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18426 * {@link #getTargetFromEvent} for this node)
18427 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18428 * @param {Event} e The event
18429 * @param {Object} data An object containing arbitrary data supplied by the drag source
18431 onNodeOut : function(n, dd, e, data){
18436 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18437 * the drop node. The default implementation returns false, so it should be overridden to provide the
18438 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18439 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18440 * {@link #getTargetFromEvent} for this node)
18441 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18442 * @param {Event} e The event
18443 * @param {Object} data An object containing arbitrary data supplied by the drag source
18444 * @return {Boolean} True if the drop was valid, else false
18446 onNodeDrop : function(n, dd, e, data){
18451 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18452 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18453 * it should be overridden to provide the proper feedback if necessary.
18454 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18455 * @param {Event} e The event
18456 * @param {Object} data An object containing arbitrary data supplied by the drag source
18457 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18458 * underlying {@link Roo.dd.StatusProxy} can be updated
18460 onContainerOver : function(dd, e, data){
18461 return this.dropNotAllowed;
18465 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18466 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18467 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18468 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18469 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18470 * @param {Event} e The event
18471 * @param {Object} data An object containing arbitrary data supplied by the drag source
18472 * @return {Boolean} True if the drop was valid, else false
18474 onContainerDrop : function(dd, e, data){
18479 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18480 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18481 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18482 * you should override this method and provide a custom implementation.
18483 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18484 * @param {Event} e The event
18485 * @param {Object} data An object containing arbitrary data supplied by the drag source
18486 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18487 * underlying {@link Roo.dd.StatusProxy} can be updated
18489 notifyEnter : function(dd, e, data){
18490 return this.dropNotAllowed;
18494 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18495 * This method will be called on every mouse movement while the drag source is over the drop zone.
18496 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18497 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18498 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18499 * registered node, it will call {@link #onContainerOver}.
18500 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18501 * @param {Event} e The event
18502 * @param {Object} data An object containing arbitrary data supplied by the drag source
18503 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18504 * underlying {@link Roo.dd.StatusProxy} can be updated
18506 notifyOver : function(dd, e, data){
18507 var n = this.getTargetFromEvent(e);
18508 if(!n){ // not over valid drop target
18509 if(this.lastOverNode){
18510 this.onNodeOut(this.lastOverNode, dd, e, data);
18511 this.lastOverNode = null;
18513 return this.onContainerOver(dd, e, data);
18515 if(this.lastOverNode != n){
18516 if(this.lastOverNode){
18517 this.onNodeOut(this.lastOverNode, dd, e, data);
18519 this.onNodeEnter(n, dd, e, data);
18520 this.lastOverNode = n;
18522 return this.onNodeOver(n, dd, e, data);
18526 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18527 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18528 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18529 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18530 * @param {Event} e The event
18531 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18533 notifyOut : function(dd, e, data){
18534 if(this.lastOverNode){
18535 this.onNodeOut(this.lastOverNode, dd, e, data);
18536 this.lastOverNode = null;
18541 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18542 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18543 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18544 * otherwise it will call {@link #onContainerDrop}.
18545 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18546 * @param {Event} e The event
18547 * @param {Object} data An object containing arbitrary data supplied by the drag source
18548 * @return {Boolean} True if the drop was valid, else false
18550 notifyDrop : function(dd, e, data){
18551 if(this.lastOverNode){
18552 this.onNodeOut(this.lastOverNode, dd, e, data);
18553 this.lastOverNode = null;
18555 var n = this.getTargetFromEvent(e);
18557 this.onNodeDrop(n, dd, e, data) :
18558 this.onContainerDrop(dd, e, data);
18562 triggerCacheRefresh : function(){
18563 Roo.dd.DDM.refreshCache(this.groups);
18567 * Ext JS Library 1.1.1
18568 * Copyright(c) 2006-2007, Ext JS, LLC.
18570 * Originally Released Under LGPL - original licence link has changed is not relivant.
18573 * <script type="text/javascript">
18578 * @class Roo.data.SortTypes
18580 * Defines the default sorting (casting?) comparison functions used when sorting data.
18582 Roo.data.SortTypes = {
18584 * Default sort that does nothing
18585 * @param {Mixed} s The value being converted
18586 * @return {Mixed} The comparison value
18588 none : function(s){
18593 * The regular expression used to strip tags
18597 stripTagsRE : /<\/?[^>]+>/gi,
18600 * Strips all HTML tags to sort on text only
18601 * @param {Mixed} s The value being converted
18602 * @return {String} The comparison value
18604 asText : function(s){
18605 return String(s).replace(this.stripTagsRE, "");
18609 * Strips all HTML tags to sort on text only - Case insensitive
18610 * @param {Mixed} s The value being converted
18611 * @return {String} The comparison value
18613 asUCText : function(s){
18614 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18618 * Case insensitive string
18619 * @param {Mixed} s The value being converted
18620 * @return {String} The comparison value
18622 asUCString : function(s) {
18623 return String(s).toUpperCase();
18628 * @param {Mixed} s The value being converted
18629 * @return {Number} The comparison value
18631 asDate : function(s) {
18635 if(s instanceof Date){
18636 return s.getTime();
18638 return Date.parse(String(s));
18643 * @param {Mixed} s The value being converted
18644 * @return {Float} The comparison value
18646 asFloat : function(s) {
18647 var val = parseFloat(String(s).replace(/,/g, ""));
18648 if(isNaN(val)) val = 0;
18654 * @param {Mixed} s The value being converted
18655 * @return {Number} The comparison value
18657 asInt : function(s) {
18658 var val = parseInt(String(s).replace(/,/g, ""));
18659 if(isNaN(val)) val = 0;
18664 * Ext JS Library 1.1.1
18665 * Copyright(c) 2006-2007, Ext JS, LLC.
18667 * Originally Released Under LGPL - original licence link has changed is not relivant.
18670 * <script type="text/javascript">
18674 * @class Roo.data.Record
18675 * Instances of this class encapsulate both record <em>definition</em> information, and record
18676 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18677 * to access Records cached in an {@link Roo.data.Store} object.<br>
18679 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18680 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18683 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18685 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18686 * {@link #create}. The parameters are the same.
18687 * @param {Array} data An associative Array of data values keyed by the field name.
18688 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18689 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18690 * not specified an integer id is generated.
18692 Roo.data.Record = function(data, id){
18693 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18698 * Generate a constructor for a specific record layout.
18699 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18700 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18701 * Each field definition object may contain the following properties: <ul>
18702 * <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,
18703 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18704 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18705 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18706 * is being used, then this is a string containing the javascript expression to reference the data relative to
18707 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18708 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18709 * this may be omitted.</p></li>
18710 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18711 * <ul><li>auto (Default, implies no conversion)</li>
18716 * <li>date</li></ul></p></li>
18717 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18718 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18719 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18720 * by the Reader into an object that will be stored in the Record. It is passed the
18721 * following parameters:<ul>
18722 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18724 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18726 * <br>usage:<br><pre><code>
18727 var TopicRecord = Roo.data.Record.create(
18728 {name: 'title', mapping: 'topic_title'},
18729 {name: 'author', mapping: 'username'},
18730 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18731 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18732 {name: 'lastPoster', mapping: 'user2'},
18733 {name: 'excerpt', mapping: 'post_text'}
18736 var myNewRecord = new TopicRecord({
18737 title: 'Do my job please',
18740 lastPost: new Date(),
18741 lastPoster: 'Animal',
18742 excerpt: 'No way dude!'
18744 myStore.add(myNewRecord);
18749 Roo.data.Record.create = function(o){
18750 var f = function(){
18751 f.superclass.constructor.apply(this, arguments);
18753 Roo.extend(f, Roo.data.Record);
18754 var p = f.prototype;
18755 p.fields = new Roo.util.MixedCollection(false, function(field){
18758 for(var i = 0, len = o.length; i < len; i++){
18759 p.fields.add(new Roo.data.Field(o[i]));
18761 f.getField = function(name){
18762 return p.fields.get(name);
18767 Roo.data.Record.AUTO_ID = 1000;
18768 Roo.data.Record.EDIT = 'edit';
18769 Roo.data.Record.REJECT = 'reject';
18770 Roo.data.Record.COMMIT = 'commit';
18772 Roo.data.Record.prototype = {
18774 * Readonly flag - true if this record has been modified.
18783 join : function(store){
18784 this.store = store;
18788 * Set the named field to the specified value.
18789 * @param {String} name The name of the field to set.
18790 * @param {Object} value The value to set the field to.
18792 set : function(name, value){
18793 if(this.data[name] == value){
18797 if(!this.modified){
18798 this.modified = {};
18800 if(typeof this.modified[name] == 'undefined'){
18801 this.modified[name] = this.data[name];
18803 this.data[name] = value;
18805 this.store.afterEdit(this);
18810 * Get the value of the named field.
18811 * @param {String} name The name of the field to get the value of.
18812 * @return {Object} The value of the field.
18814 get : function(name){
18815 return this.data[name];
18819 beginEdit : function(){
18820 this.editing = true;
18821 this.modified = {};
18825 cancelEdit : function(){
18826 this.editing = false;
18827 delete this.modified;
18831 endEdit : function(){
18832 this.editing = false;
18833 if(this.dirty && this.store){
18834 this.store.afterEdit(this);
18839 * Usually called by the {@link Roo.data.Store} which owns the Record.
18840 * Rejects all changes made to the Record since either creation, or the last commit operation.
18841 * Modified fields are reverted to their original values.
18843 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18844 * of reject operations.
18846 reject : function(){
18847 var m = this.modified;
18849 if(typeof m[n] != "function"){
18850 this.data[n] = m[n];
18853 this.dirty = false;
18854 delete this.modified;
18855 this.editing = false;
18857 this.store.afterReject(this);
18862 * Usually called by the {@link Roo.data.Store} which owns the Record.
18863 * Commits all changes made to the Record since either creation, or the last commit operation.
18865 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18866 * of commit operations.
18868 commit : function(){
18869 this.dirty = false;
18870 delete this.modified;
18871 this.editing = false;
18873 this.store.afterCommit(this);
18878 hasError : function(){
18879 return this.error != null;
18883 clearError : function(){
18888 * Creates a copy of this record.
18889 * @param {String} id (optional) A new record id if you don't want to use this record's id
18892 copy : function(newId) {
18893 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
18897 * Ext JS Library 1.1.1
18898 * Copyright(c) 2006-2007, Ext JS, LLC.
18900 * Originally Released Under LGPL - original licence link has changed is not relivant.
18903 * <script type="text/javascript">
18909 * @class Roo.data.Store
18910 * @extends Roo.util.Observable
18911 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
18912 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
18914 * 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
18915 * has no knowledge of the format of the data returned by the Proxy.<br>
18917 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
18918 * instances from the data object. These records are cached and made available through accessor functions.
18920 * Creates a new Store.
18921 * @param {Object} config A config object containing the objects needed for the Store to access data,
18922 * and read the data into Records.
18924 Roo.data.Store = function(config){
18925 this.data = new Roo.util.MixedCollection(false);
18926 this.data.getKey = function(o){
18929 this.baseParams = {};
18931 this.paramNames = {
18938 if(config && config.data){
18939 this.inlineData = config.data;
18940 delete config.data;
18943 Roo.apply(this, config);
18945 if(this.reader){ // reader passed
18946 this.reader = Roo.factory(this.reader, Roo.data);
18947 this.reader.xmodule = this.xmodule || false;
18948 if(!this.recordType){
18949 this.recordType = this.reader.recordType;
18951 if(this.reader.onMetaChange){
18952 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
18956 if(this.recordType){
18957 this.fields = this.recordType.prototype.fields;
18959 this.modified = [];
18963 * @event datachanged
18964 * Fires when the data cache has changed, and a widget which is using this Store
18965 * as a Record cache should refresh its view.
18966 * @param {Store} this
18968 datachanged : true,
18970 * @event metachange
18971 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
18972 * @param {Store} this
18973 * @param {Object} meta The JSON metadata
18978 * Fires when Records have been added to the Store
18979 * @param {Store} this
18980 * @param {Roo.data.Record[]} records The array of Records added
18981 * @param {Number} index The index at which the record(s) were added
18986 * Fires when a Record has been removed from the Store
18987 * @param {Store} this
18988 * @param {Roo.data.Record} record The Record that was removed
18989 * @param {Number} index The index at which the record was removed
18994 * Fires when a Record has been updated
18995 * @param {Store} this
18996 * @param {Roo.data.Record} record The Record that was updated
18997 * @param {String} operation The update operation being performed. Value may be one of:
18999 Roo.data.Record.EDIT
19000 Roo.data.Record.REJECT
19001 Roo.data.Record.COMMIT
19007 * Fires when the data cache has been cleared.
19008 * @param {Store} this
19012 * @event beforeload
19013 * Fires before a request is made for a new data object. If the beforeload handler returns false
19014 * the load action will be canceled.
19015 * @param {Store} this
19016 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19021 * Fires after a new set of Records has been loaded.
19022 * @param {Store} this
19023 * @param {Roo.data.Record[]} records The Records that were loaded
19024 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19028 * @event loadexception
19029 * Fires if an exception occurs in the Proxy during loading.
19030 * Called with the signature of the Proxy's "loadexception" event.
19031 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19034 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19035 * @param {Object} load options
19036 * @param {Object} jsonData from your request (normally this contains the Exception)
19038 loadexception : true
19042 this.proxy = Roo.factory(this.proxy, Roo.data);
19043 this.proxy.xmodule = this.xmodule || false;
19044 this.relayEvents(this.proxy, ["loadexception"]);
19046 this.sortToggle = {};
19048 Roo.data.Store.superclass.constructor.call(this);
19050 if(this.inlineData){
19051 this.loadData(this.inlineData);
19052 delete this.inlineData;
19055 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19057 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19058 * without a remote query - used by combo/forms at present.
19062 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19065 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19068 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19069 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19072 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19073 * on any HTTP request
19076 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19079 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19080 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19082 remoteSort : false,
19085 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19086 * loaded or when a record is removed. (defaults to false).
19088 pruneModifiedRecords : false,
19091 lastOptions : null,
19094 * Add Records to the Store and fires the add event.
19095 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19097 add : function(records){
19098 records = [].concat(records);
19099 for(var i = 0, len = records.length; i < len; i++){
19100 records[i].join(this);
19102 var index = this.data.length;
19103 this.data.addAll(records);
19104 this.fireEvent("add", this, records, index);
19108 * Remove a Record from the Store and fires the remove event.
19109 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19111 remove : function(record){
19112 var index = this.data.indexOf(record);
19113 this.data.removeAt(index);
19114 if(this.pruneModifiedRecords){
19115 this.modified.remove(record);
19117 this.fireEvent("remove", this, record, index);
19121 * Remove all Records from the Store and fires the clear event.
19123 removeAll : function(){
19125 if(this.pruneModifiedRecords){
19126 this.modified = [];
19128 this.fireEvent("clear", this);
19132 * Inserts Records to the Store at the given index and fires the add event.
19133 * @param {Number} index The start index at which to insert the passed Records.
19134 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19136 insert : function(index, records){
19137 records = [].concat(records);
19138 for(var i = 0, len = records.length; i < len; i++){
19139 this.data.insert(index, records[i]);
19140 records[i].join(this);
19142 this.fireEvent("add", this, records, index);
19146 * Get the index within the cache of the passed Record.
19147 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19148 * @return {Number} The index of the passed Record. Returns -1 if not found.
19150 indexOf : function(record){
19151 return this.data.indexOf(record);
19155 * Get the index within the cache of the Record with the passed id.
19156 * @param {String} id The id of the Record to find.
19157 * @return {Number} The index of the Record. Returns -1 if not found.
19159 indexOfId : function(id){
19160 return this.data.indexOfKey(id);
19164 * Get the Record with the specified id.
19165 * @param {String} id The id of the Record to find.
19166 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19168 getById : function(id){
19169 return this.data.key(id);
19173 * Get the Record at the specified index.
19174 * @param {Number} index The index of the Record to find.
19175 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19177 getAt : function(index){
19178 return this.data.itemAt(index);
19182 * Returns a range of Records between specified indices.
19183 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19184 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19185 * @return {Roo.data.Record[]} An array of Records
19187 getRange : function(start, end){
19188 return this.data.getRange(start, end);
19192 storeOptions : function(o){
19193 o = Roo.apply({}, o);
19196 this.lastOptions = o;
19200 * Loads the Record cache from the configured Proxy using the configured Reader.
19202 * If using remote paging, then the first load call must specify the <em>start</em>
19203 * and <em>limit</em> properties in the options.params property to establish the initial
19204 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19206 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19207 * and this call will return before the new data has been loaded. Perform any post-processing
19208 * in a callback function, or in a "load" event handler.</strong>
19210 * @param {Object} options An object containing properties which control loading options:<ul>
19211 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19212 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19213 * passed the following arguments:<ul>
19214 * <li>r : Roo.data.Record[]</li>
19215 * <li>options: Options object from the load call</li>
19216 * <li>success: Boolean success indicator</li></ul></li>
19217 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19218 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19221 load : function(options){
19222 options = options || {};
19223 if(this.fireEvent("beforeload", this, options) !== false){
19224 this.storeOptions(options);
19225 var p = Roo.apply(options.params || {}, this.baseParams);
19226 if(this.sortInfo && this.remoteSort){
19227 var pn = this.paramNames;
19228 p[pn["sort"]] = this.sortInfo.field;
19229 p[pn["dir"]] = this.sortInfo.direction;
19231 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19236 * Reloads the Record cache from the configured Proxy using the configured Reader and
19237 * the options from the last load operation performed.
19238 * @param {Object} options (optional) An object containing properties which may override the options
19239 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19240 * the most recently used options are reused).
19242 reload : function(options){
19243 this.load(Roo.applyIf(options||{}, this.lastOptions));
19247 // Called as a callback by the Reader during a load operation.
19248 loadRecords : function(o, options, success){
19249 if(!o || success === false){
19250 if(success !== false){
19251 this.fireEvent("load", this, [], options);
19253 if(options.callback){
19254 options.callback.call(options.scope || this, [], options, false);
19258 // if data returned failure - throw an exception.
19259 if (o.success === false) {
19260 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19263 var r = o.records, t = o.totalRecords || r.length;
19264 if(!options || options.add !== true){
19265 if(this.pruneModifiedRecords){
19266 this.modified = [];
19268 for(var i = 0, len = r.length; i < len; i++){
19272 this.data = this.snapshot;
19273 delete this.snapshot;
19276 this.data.addAll(r);
19277 this.totalLength = t;
19279 this.fireEvent("datachanged", this);
19281 this.totalLength = Math.max(t, this.data.length+r.length);
19284 this.fireEvent("load", this, r, options);
19285 if(options.callback){
19286 options.callback.call(options.scope || this, r, options, true);
19291 * Loads data from a passed data block. A Reader which understands the format of the data
19292 * must have been configured in the constructor.
19293 * @param {Object} data The data block from which to read the Records. The format of the data expected
19294 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19295 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19297 loadData : function(o, append){
19298 var r = this.reader.readRecords(o);
19299 this.loadRecords(r, {add: append}, true);
19303 * Gets the number of cached records.
19305 * <em>If using paging, this may not be the total size of the dataset. If the data object
19306 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19307 * the data set size</em>
19309 getCount : function(){
19310 return this.data.length || 0;
19314 * Gets the total number of records in the dataset as returned by the server.
19316 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19317 * the dataset size</em>
19319 getTotalCount : function(){
19320 return this.totalLength || 0;
19324 * Returns the sort state of the Store as an object with two properties:
19326 field {String} The name of the field by which the Records are sorted
19327 direction {String} The sort order, "ASC" or "DESC"
19330 getSortState : function(){
19331 return this.sortInfo;
19335 applySort : function(){
19336 if(this.sortInfo && !this.remoteSort){
19337 var s = this.sortInfo, f = s.field;
19338 var st = this.fields.get(f).sortType;
19339 var fn = function(r1, r2){
19340 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19341 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19343 this.data.sort(s.direction, fn);
19344 if(this.snapshot && this.snapshot != this.data){
19345 this.snapshot.sort(s.direction, fn);
19351 * Sets the default sort column and order to be used by the next load operation.
19352 * @param {String} fieldName The name of the field to sort by.
19353 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19355 setDefaultSort : function(field, dir){
19356 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19360 * Sort the Records.
19361 * If remote sorting is used, the sort is performed on the server, and the cache is
19362 * reloaded. If local sorting is used, the cache is sorted internally.
19363 * @param {String} fieldName The name of the field to sort by.
19364 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19366 sort : function(fieldName, dir){
19367 var f = this.fields.get(fieldName);
19369 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19370 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19375 this.sortToggle[f.name] = dir;
19376 this.sortInfo = {field: f.name, direction: dir};
19377 if(!this.remoteSort){
19379 this.fireEvent("datachanged", this);
19381 this.load(this.lastOptions);
19386 * Calls the specified function for each of the Records in the cache.
19387 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19388 * Returning <em>false</em> aborts and exits the iteration.
19389 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19391 each : function(fn, scope){
19392 this.data.each(fn, scope);
19396 * Gets all records modified since the last commit. Modified records are persisted across load operations
19397 * (e.g., during paging).
19398 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19400 getModifiedRecords : function(){
19401 return this.modified;
19405 createFilterFn : function(property, value, anyMatch){
19406 if(!value.exec){ // not a regex
19407 value = String(value);
19408 if(value.length == 0){
19411 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19413 return function(r){
19414 return value.test(r.data[property]);
19419 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19420 * @param {String} property A field on your records
19421 * @param {Number} start The record index to start at (defaults to 0)
19422 * @param {Number} end The last record index to include (defaults to length - 1)
19423 * @return {Number} The sum
19425 sum : function(property, start, end){
19426 var rs = this.data.items, v = 0;
19427 start = start || 0;
19428 end = (end || end === 0) ? end : rs.length-1;
19430 for(var i = start; i <= end; i++){
19431 v += (rs[i].data[property] || 0);
19437 * Filter the records by a specified property.
19438 * @param {String} field A field on your records
19439 * @param {String/RegExp} value Either a string that the field
19440 * should start with or a RegExp to test against the field
19441 * @param {Boolean} anyMatch True to match any part not just the beginning
19443 filter : function(property, value, anyMatch){
19444 var fn = this.createFilterFn(property, value, anyMatch);
19445 return fn ? this.filterBy(fn) : this.clearFilter();
19449 * Filter by a function. The specified function will be called with each
19450 * record in this data source. If the function returns true the record is included,
19451 * otherwise it is filtered.
19452 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19453 * @param {Object} scope (optional) The scope of the function (defaults to this)
19455 filterBy : function(fn, scope){
19456 this.snapshot = this.snapshot || this.data;
19457 this.data = this.queryBy(fn, scope||this);
19458 this.fireEvent("datachanged", this);
19462 * Query the records by a specified property.
19463 * @param {String} field A field on your records
19464 * @param {String/RegExp} value Either a string that the field
19465 * should start with or a RegExp to test against the field
19466 * @param {Boolean} anyMatch True to match any part not just the beginning
19467 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19469 query : function(property, value, anyMatch){
19470 var fn = this.createFilterFn(property, value, anyMatch);
19471 return fn ? this.queryBy(fn) : this.data.clone();
19475 * Query by a function. The specified function will be called with each
19476 * record in this data source. If the function returns true the record is included
19478 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19479 * @param {Object} scope (optional) The scope of the function (defaults to this)
19480 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19482 queryBy : function(fn, scope){
19483 var data = this.snapshot || this.data;
19484 return data.filterBy(fn, scope||this);
19488 * Collects unique values for a particular dataIndex from this store.
19489 * @param {String} dataIndex The property to collect
19490 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19491 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19492 * @return {Array} An array of the unique values
19494 collect : function(dataIndex, allowNull, bypassFilter){
19495 var d = (bypassFilter === true && this.snapshot) ?
19496 this.snapshot.items : this.data.items;
19497 var v, sv, r = [], l = {};
19498 for(var i = 0, len = d.length; i < len; i++){
19499 v = d[i].data[dataIndex];
19501 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19510 * Revert to a view of the Record cache with no filtering applied.
19511 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19513 clearFilter : function(suppressEvent){
19514 if(this.snapshot && this.snapshot != this.data){
19515 this.data = this.snapshot;
19516 delete this.snapshot;
19517 if(suppressEvent !== true){
19518 this.fireEvent("datachanged", this);
19524 afterEdit : function(record){
19525 if(this.modified.indexOf(record) == -1){
19526 this.modified.push(record);
19528 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19532 afterReject : function(record){
19533 this.modified.remove(record);
19534 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19538 afterCommit : function(record){
19539 this.modified.remove(record);
19540 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19544 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19545 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19547 commitChanges : function(){
19548 var m = this.modified.slice(0);
19549 this.modified = [];
19550 for(var i = 0, len = m.length; i < len; i++){
19556 * Cancel outstanding changes on all changed records.
19558 rejectChanges : function(){
19559 var m = this.modified.slice(0);
19560 this.modified = [];
19561 for(var i = 0, len = m.length; i < len; i++){
19566 onMetaChange : function(meta, rtype, o){
19567 this.recordType = rtype;
19568 this.fields = rtype.prototype.fields;
19569 delete this.snapshot;
19570 this.sortInfo = meta.sortInfo;
19571 this.modified = [];
19572 this.fireEvent('metachange', this, this.reader.meta);
19576 * Ext JS Library 1.1.1
19577 * Copyright(c) 2006-2007, Ext JS, LLC.
19579 * Originally Released Under LGPL - original licence link has changed is not relivant.
19582 * <script type="text/javascript">
19586 * @class Roo.data.SimpleStore
19587 * @extends Roo.data.Store
19588 * Small helper class to make creating Stores from Array data easier.
19589 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19590 * @cfg {Array} fields An array of field definition objects, or field name strings.
19591 * @cfg {Array} data The multi-dimensional array of data
19593 * @param {Object} config
19595 Roo.data.SimpleStore = function(config){
19596 Roo.data.SimpleStore.superclass.constructor.call(this, {
19598 reader: new Roo.data.ArrayReader({
19601 Roo.data.Record.create(config.fields)
19603 proxy : new Roo.data.MemoryProxy(config.data)
19607 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19609 * Ext JS Library 1.1.1
19610 * Copyright(c) 2006-2007, Ext JS, LLC.
19612 * Originally Released Under LGPL - original licence link has changed is not relivant.
19615 * <script type="text/javascript">
19620 * @extends Roo.data.Store
19621 * @class Roo.data.JsonStore
19622 * Small helper class to make creating Stores for JSON data easier. <br/>
19624 var store = new Roo.data.JsonStore({
19625 url: 'get-images.php',
19627 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19630 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19631 * JsonReader and HttpProxy (unless inline data is provided).</b>
19632 * @cfg {Array} fields An array of field definition objects, or field name strings.
19634 * @param {Object} config
19636 Roo.data.JsonStore = function(c){
19637 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19638 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19639 reader: new Roo.data.JsonReader(c, c.fields)
19642 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19644 * Ext JS Library 1.1.1
19645 * Copyright(c) 2006-2007, Ext JS, LLC.
19647 * Originally Released Under LGPL - original licence link has changed is not relivant.
19650 * <script type="text/javascript">
19654 Roo.data.Field = function(config){
19655 if(typeof config == "string"){
19656 config = {name: config};
19658 Roo.apply(this, config);
19661 this.type = "auto";
19664 var st = Roo.data.SortTypes;
19665 // named sortTypes are supported, here we look them up
19666 if(typeof this.sortType == "string"){
19667 this.sortType = st[this.sortType];
19670 // set default sortType for strings and dates
19671 if(!this.sortType){
19674 this.sortType = st.asUCString;
19677 this.sortType = st.asDate;
19680 this.sortType = st.none;
19685 var stripRe = /[\$,%]/g;
19687 // prebuilt conversion function for this field, instead of
19688 // switching every time we're reading a value
19690 var cv, dateFormat = this.dateFormat;
19695 cv = function(v){ return v; };
19698 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19702 return v !== undefined && v !== null && v !== '' ?
19703 parseInt(String(v).replace(stripRe, ""), 10) : '';
19708 return v !== undefined && v !== null && v !== '' ?
19709 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19714 cv = function(v){ return v === true || v === "true" || v == 1; };
19721 if(v instanceof Date){
19725 if(dateFormat == "timestamp"){
19726 return new Date(v*1000);
19728 return Date.parseDate(v, dateFormat);
19730 var parsed = Date.parse(v);
19731 return parsed ? new Date(parsed) : null;
19740 Roo.data.Field.prototype = {
19748 * Ext JS Library 1.1.1
19749 * Copyright(c) 2006-2007, Ext JS, LLC.
19751 * Originally Released Under LGPL - original licence link has changed is not relivant.
19754 * <script type="text/javascript">
19757 // Base class for reading structured data from a data source. This class is intended to be
19758 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19761 * @class Roo.data.DataReader
19762 * Base class for reading structured data from a data source. This class is intended to be
19763 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19766 Roo.data.DataReader = function(meta, recordType){
19770 this.recordType = recordType instanceof Array ?
19771 Roo.data.Record.create(recordType) : recordType;
19774 Roo.data.DataReader.prototype = {
19776 * Create an empty record
19777 * @param {Object} data (optional) - overlay some values
19778 * @return {Roo.data.Record} record created.
19780 newRow : function(d) {
19782 this.recordType.prototype.fields.each(function(c) {
19784 case 'int' : da[c.name] = 0; break;
19785 case 'date' : da[c.name] = new Date(); break;
19786 case 'float' : da[c.name] = 0.0; break;
19787 case 'boolean' : da[c.name] = false; break;
19788 default : da[c.name] = ""; break;
19792 return new this.recordType(Roo.apply(da, d));
19797 * Ext JS Library 1.1.1
19798 * Copyright(c) 2006-2007, Ext JS, LLC.
19800 * Originally Released Under LGPL - original licence link has changed is not relivant.
19803 * <script type="text/javascript">
19807 * @class Roo.data.DataProxy
19808 * @extends Roo.data.Observable
19809 * This class is an abstract base class for implementations which provide retrieval of
19810 * unformatted data objects.<br>
19812 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19813 * (of the appropriate type which knows how to parse the data object) to provide a block of
19814 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19816 * Custom implementations must implement the load method as described in
19817 * {@link Roo.data.HttpProxy#load}.
19819 Roo.data.DataProxy = function(){
19822 * @event beforeload
19823 * Fires before a network request is made to retrieve a data object.
19824 * @param {Object} This DataProxy object.
19825 * @param {Object} params The params parameter to the load function.
19830 * Fires before the load method's callback is called.
19831 * @param {Object} This DataProxy object.
19832 * @param {Object} o The data object.
19833 * @param {Object} arg The callback argument object passed to the load function.
19837 * @event loadexception
19838 * Fires if an Exception occurs during data retrieval.
19839 * @param {Object} This DataProxy object.
19840 * @param {Object} o The data object.
19841 * @param {Object} arg The callback argument object passed to the load function.
19842 * @param {Object} e The Exception.
19844 loadexception : true
19846 Roo.data.DataProxy.superclass.constructor.call(this);
19849 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
19852 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
19856 * Ext JS Library 1.1.1
19857 * Copyright(c) 2006-2007, Ext JS, LLC.
19859 * Originally Released Under LGPL - original licence link has changed is not relivant.
19862 * <script type="text/javascript">
19865 * @class Roo.data.MemoryProxy
19866 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
19867 * to the Reader when its load method is called.
19869 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
19871 Roo.data.MemoryProxy = function(data){
19875 Roo.data.MemoryProxy.superclass.constructor.call(this);
19879 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
19881 * Load data from the requested source (in this case an in-memory
19882 * data object passed to the constructor), read the data object into
19883 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
19884 * process that block using the passed callback.
19885 * @param {Object} params This parameter is not used by the MemoryProxy class.
19886 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19887 * object into a block of Roo.data.Records.
19888 * @param {Function} callback The function into which to pass the block of Roo.data.records.
19889 * The function must be passed <ul>
19890 * <li>The Record block object</li>
19891 * <li>The "arg" argument from the load function</li>
19892 * <li>A boolean success indicator</li>
19894 * @param {Object} scope The scope in which to call the callback
19895 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19897 load : function(params, reader, callback, scope, arg){
19898 params = params || {};
19901 result = reader.readRecords(this.data);
19903 this.fireEvent("loadexception", this, arg, null, e);
19904 callback.call(scope, null, arg, false);
19907 callback.call(scope, result, arg, true);
19911 update : function(params, records){
19916 * Ext JS Library 1.1.1
19917 * Copyright(c) 2006-2007, Ext JS, LLC.
19919 * Originally Released Under LGPL - original licence link has changed is not relivant.
19922 * <script type="text/javascript">
19925 * @class Roo.data.HttpProxy
19926 * @extends Roo.data.DataProxy
19927 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
19928 * configured to reference a certain URL.<br><br>
19930 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
19931 * from which the running page was served.<br><br>
19933 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
19935 * Be aware that to enable the browser to parse an XML document, the server must set
19936 * the Content-Type header in the HTTP response to "text/xml".
19938 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
19939 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
19940 * will be used to make the request.
19942 Roo.data.HttpProxy = function(conn){
19943 Roo.data.HttpProxy.superclass.constructor.call(this);
19944 // is conn a conn config or a real conn?
19946 this.useAjax = !conn || !conn.events;
19950 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
19951 // thse are take from connection...
19954 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
19957 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
19958 * extra parameters to each request made by this object. (defaults to undefined)
19961 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
19962 * to each request made by this object. (defaults to undefined)
19965 * @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)
19968 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
19971 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
19977 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
19981 * Return the {@link Roo.data.Connection} object being used by this Proxy.
19982 * @return {Connection} The Connection object. This object may be used to subscribe to events on
19983 * a finer-grained basis than the DataProxy events.
19985 getConnection : function(){
19986 return this.useAjax ? Roo.Ajax : this.conn;
19990 * Load data from the configured {@link Roo.data.Connection}, read the data object into
19991 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
19992 * process that block using the passed callback.
19993 * @param {Object} params An object containing properties which are to be used as HTTP parameters
19994 * for the request to the remote server.
19995 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19996 * object into a block of Roo.data.Records.
19997 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
19998 * The function must be passed <ul>
19999 * <li>The Record block object</li>
20000 * <li>The "arg" argument from the load function</li>
20001 * <li>A boolean success indicator</li>
20003 * @param {Object} scope The scope in which to call the callback
20004 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20006 load : function(params, reader, callback, scope, arg){
20007 if(this.fireEvent("beforeload", this, params) !== false){
20009 params : params || {},
20011 callback : callback,
20016 callback : this.loadResponse,
20020 Roo.applyIf(o, this.conn);
20021 if(this.activeRequest){
20022 Roo.Ajax.abort(this.activeRequest);
20024 this.activeRequest = Roo.Ajax.request(o);
20026 this.conn.request(o);
20029 callback.call(scope||this, null, arg, false);
20034 loadResponse : function(o, success, response){
20035 delete this.activeRequest;
20037 this.fireEvent("loadexception", this, o, response);
20038 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20043 result = o.reader.read(response);
20045 this.fireEvent("loadexception", this, o, response, e);
20046 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20050 this.fireEvent("load", this, o, o.request.arg);
20051 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20055 update : function(dataSet){
20060 updateResponse : function(dataSet){
20065 * Ext JS Library 1.1.1
20066 * Copyright(c) 2006-2007, Ext JS, LLC.
20068 * Originally Released Under LGPL - original licence link has changed is not relivant.
20071 * <script type="text/javascript">
20075 * @class Roo.data.ScriptTagProxy
20076 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20077 * other than the originating domain of the running page.<br><br>
20079 * <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
20080 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20082 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20083 * source code that is used as the source inside a <script> tag.<br><br>
20085 * In order for the browser to process the returned data, the server must wrap the data object
20086 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20087 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20088 * depending on whether the callback name was passed:
20091 boolean scriptTag = false;
20092 String cb = request.getParameter("callback");
20095 response.setContentType("text/javascript");
20097 response.setContentType("application/x-json");
20099 Writer out = response.getWriter();
20101 out.write(cb + "(");
20103 out.print(dataBlock.toJsonString());
20110 * @param {Object} config A configuration object.
20112 Roo.data.ScriptTagProxy = function(config){
20113 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20114 Roo.apply(this, config);
20115 this.head = document.getElementsByTagName("head")[0];
20118 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20120 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20122 * @cfg {String} url The URL from which to request the data object.
20125 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20129 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20130 * the server the name of the callback function set up by the load call to process the returned data object.
20131 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20132 * javascript output which calls this named function passing the data object as its only parameter.
20134 callbackParam : "callback",
20136 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20137 * name to the request.
20142 * Load data from the configured URL, read the data object into
20143 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20144 * process that block using the passed callback.
20145 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20146 * for the request to the remote server.
20147 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20148 * object into a block of Roo.data.Records.
20149 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20150 * The function must be passed <ul>
20151 * <li>The Record block object</li>
20152 * <li>The "arg" argument from the load function</li>
20153 * <li>A boolean success indicator</li>
20155 * @param {Object} scope The scope in which to call the callback
20156 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20158 load : function(params, reader, callback, scope, arg){
20159 if(this.fireEvent("beforeload", this, params) !== false){
20161 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20163 var url = this.url;
20164 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20166 url += "&_dc=" + (new Date().getTime());
20168 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20171 cb : "stcCallback"+transId,
20172 scriptId : "stcScript"+transId,
20176 callback : callback,
20182 window[trans.cb] = function(o){
20183 conn.handleResponse(o, trans);
20186 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20188 if(this.autoAbort !== false){
20192 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20194 var script = document.createElement("script");
20195 script.setAttribute("src", url);
20196 script.setAttribute("type", "text/javascript");
20197 script.setAttribute("id", trans.scriptId);
20198 this.head.appendChild(script);
20200 this.trans = trans;
20202 callback.call(scope||this, null, arg, false);
20207 isLoading : function(){
20208 return this.trans ? true : false;
20212 * Abort the current server request.
20214 abort : function(){
20215 if(this.isLoading()){
20216 this.destroyTrans(this.trans);
20221 destroyTrans : function(trans, isLoaded){
20222 this.head.removeChild(document.getElementById(trans.scriptId));
20223 clearTimeout(trans.timeoutId);
20225 window[trans.cb] = undefined;
20227 delete window[trans.cb];
20230 // if hasn't been loaded, wait for load to remove it to prevent script error
20231 window[trans.cb] = function(){
20232 window[trans.cb] = undefined;
20234 delete window[trans.cb];
20241 handleResponse : function(o, trans){
20242 this.trans = false;
20243 this.destroyTrans(trans, true);
20246 result = trans.reader.readRecords(o);
20248 this.fireEvent("loadexception", this, o, trans.arg, e);
20249 trans.callback.call(trans.scope||window, null, trans.arg, false);
20252 this.fireEvent("load", this, o, trans.arg);
20253 trans.callback.call(trans.scope||window, result, trans.arg, true);
20257 handleFailure : function(trans){
20258 this.trans = false;
20259 this.destroyTrans(trans, false);
20260 this.fireEvent("loadexception", this, null, trans.arg);
20261 trans.callback.call(trans.scope||window, null, trans.arg, false);
20265 * Ext JS Library 1.1.1
20266 * Copyright(c) 2006-2007, Ext JS, LLC.
20268 * Originally Released Under LGPL - original licence link has changed is not relivant.
20271 * <script type="text/javascript">
20275 * @class Roo.data.JsonReader
20276 * @extends Roo.data.DataReader
20277 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20278 * based on mappings in a provided Roo.data.Record constructor.
20282 var RecordDef = Roo.data.Record.create([
20283 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20284 {name: 'occupation'} // This field will use "occupation" as the mapping.
20286 var myReader = new Roo.data.JsonReader({
20287 totalProperty: "results", // The property which contains the total dataset size (optional)
20288 root: "rows", // The property which contains an Array of row objects
20289 id: "id" // The property within each row object that provides an ID for the record (optional)
20293 * This would consume a JSON file like this:
20295 { 'results': 2, 'rows': [
20296 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20297 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20300 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20301 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20302 * paged from the remote server.
20303 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20304 * @cfg {String} root name of the property which contains the Array of row objects.
20305 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20307 * Create a new JsonReader
20308 * @param {Object} meta Metadata configuration options
20309 * @param {Object} recordType Either an Array of field definition objects,
20310 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20312 Roo.data.JsonReader = function(meta, recordType){
20315 // set some defaults:
20316 Roo.applyIf(meta, {
20317 totalProperty: 'total',
20318 successProperty : 'success',
20323 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20325 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20327 * This method is only used by a DataProxy which has retrieved data from a remote server.
20328 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20329 * @return {Object} data A data block which is used by an Roo.data.Store object as
20330 * a cache of Roo.data.Records.
20332 read : function(response){
20333 var json = response.responseText;
20335 var o = eval("("+json+")");
20337 throw {message: "JsonReader.read: Json object not found"};
20342 this.meta = o.metaData;
20343 this.recordType = Roo.data.Record.create(o.metaData.fields);
20344 this.onMetaChange(this.meta, this.recordType, o);
20346 return this.readRecords(o);
20349 // private function a store will implement
20350 onMetaChange : function(meta, recordType, o){
20357 simpleAccess: function(obj, subsc) {
20364 getJsonAccessor: function(){
20366 return function(expr) {
20368 return(re.test(expr))
20369 ? new Function("obj", "return obj." + expr)
20374 return Roo.emptyFn;
20379 * Create a data block containing Roo.data.Records from an XML document.
20380 * @param {Object} o An object which contains an Array of row objects in the property specified
20381 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20382 * which contains the total size of the dataset.
20383 * @return {Object} data A data block which is used by an Roo.data.Store object as
20384 * a cache of Roo.data.Records.
20386 readRecords : function(o){
20388 * After any data loads, the raw JSON data is available for further custom processing.
20392 var s = this.meta, Record = this.recordType,
20393 f = Record.prototype.fields, fi = f.items, fl = f.length;
20395 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20397 if(s.totalProperty) {
20398 this.getTotal = this.getJsonAccessor(s.totalProperty);
20400 if(s.successProperty) {
20401 this.getSuccess = this.getJsonAccessor(s.successProperty);
20403 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20405 var g = this.getJsonAccessor(s.id);
20406 this.getId = function(rec) {
20408 return (r === undefined || r === "") ? null : r;
20411 this.getId = function(){return null;};
20414 for(var i = 0; i < fl; i++){
20416 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20417 this.ef[i] = this.getJsonAccessor(map);
20421 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20422 if(s.totalProperty){
20423 var v = parseInt(this.getTotal(o), 10);
20428 if(s.successProperty){
20429 var v = this.getSuccess(o);
20430 if(v === false || v === 'false'){
20435 for(var i = 0; i < c; i++){
20438 var id = this.getId(n);
20439 for(var j = 0; j < fl; j++){
20441 var v = this.ef[j](n);
20442 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20444 var record = new Record(values, id);
20446 records[i] = record;
20451 totalRecords : totalRecords
20456 * Ext JS Library 1.1.1
20457 * Copyright(c) 2006-2007, Ext JS, LLC.
20459 * Originally Released Under LGPL - original licence link has changed is not relivant.
20462 * <script type="text/javascript">
20466 * @class Roo.data.XmlReader
20467 * @extends Roo.data.DataReader
20468 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20469 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20471 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20472 * header in the HTTP response must be set to "text/xml".</em>
20476 var RecordDef = Roo.data.Record.create([
20477 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20478 {name: 'occupation'} // This field will use "occupation" as the mapping.
20480 var myReader = new Roo.data.XmlReader({
20481 totalRecords: "results", // The element which contains the total dataset size (optional)
20482 record: "row", // The repeated element which contains row information
20483 id: "id" // The element within the row that provides an ID for the record (optional)
20487 * This would consume an XML file like this:
20491 <results>2</results>
20494 <name>Bill</name>
20495 <occupation>Gardener</occupation>
20499 <name>Ben</name>
20500 <occupation>Horticulturalist</occupation>
20504 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20505 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20506 * paged from the remote server.
20507 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20508 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20509 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20510 * a record identifier value.
20512 * Create a new XmlReader
20513 * @param {Object} meta Metadata configuration options
20514 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20515 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20516 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20518 Roo.data.XmlReader = function(meta, recordType){
20520 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20522 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20524 * This method is only used by a DataProxy which has retrieved data from a remote server.
20525 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20526 * to contain a method called 'responseXML' that returns an XML document object.
20527 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20528 * a cache of Roo.data.Records.
20530 read : function(response){
20531 var doc = response.responseXML;
20533 throw {message: "XmlReader.read: XML Document not available"};
20535 return this.readRecords(doc);
20539 * Create a data block containing Roo.data.Records from an XML document.
20540 * @param {Object} doc A parsed XML document.
20541 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20542 * a cache of Roo.data.Records.
20544 readRecords : function(doc){
20546 * After any data loads/reads, the raw XML Document is available for further custom processing.
20547 * @type XMLDocument
20549 this.xmlData = doc;
20550 var root = doc.documentElement || doc;
20551 var q = Roo.DomQuery;
20552 var recordType = this.recordType, fields = recordType.prototype.fields;
20553 var sid = this.meta.id;
20554 var totalRecords = 0, success = true;
20555 if(this.meta.totalRecords){
20556 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20559 if(this.meta.success){
20560 var sv = q.selectValue(this.meta.success, root, true);
20561 success = sv !== false && sv !== 'false';
20564 var ns = q.select(this.meta.record, root);
20565 for(var i = 0, len = ns.length; i < len; i++) {
20568 var id = sid ? q.selectValue(sid, n) : undefined;
20569 for(var j = 0, jlen = fields.length; j < jlen; j++){
20570 var f = fields.items[j];
20571 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20573 values[f.name] = v;
20575 var record = new recordType(values, id);
20577 records[records.length] = record;
20583 totalRecords : totalRecords || records.length
20588 * Ext JS Library 1.1.1
20589 * Copyright(c) 2006-2007, Ext JS, LLC.
20591 * Originally Released Under LGPL - original licence link has changed is not relivant.
20594 * <script type="text/javascript">
20598 * @class Roo.data.ArrayReader
20599 * @extends Roo.data.DataReader
20600 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20601 * Each element of that Array represents a row of data fields. The
20602 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20603 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20607 var RecordDef = Roo.data.Record.create([
20608 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20609 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20611 var myReader = new Roo.data.ArrayReader({
20612 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20616 * This would consume an Array like this:
20618 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20620 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20622 * Create a new JsonReader
20623 * @param {Object} meta Metadata configuration options.
20624 * @param {Object} recordType Either an Array of field definition objects
20625 * as specified to {@link Roo.data.Record#create},
20626 * or an {@link Roo.data.Record} object
20627 * created using {@link Roo.data.Record#create}.
20629 Roo.data.ArrayReader = function(meta, recordType){
20630 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20633 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20635 * Create a data block containing Roo.data.Records from an XML document.
20636 * @param {Object} o An Array of row objects which represents the dataset.
20637 * @return {Object} data A data block which is used by an Roo.data.Store object as
20638 * a cache of Roo.data.Records.
20640 readRecords : function(o){
20641 var sid = this.meta ? this.meta.id : null;
20642 var recordType = this.recordType, fields = recordType.prototype.fields;
20645 for(var i = 0; i < root.length; i++){
20648 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20649 for(var j = 0, jlen = fields.length; j < jlen; j++){
20650 var f = fields.items[j];
20651 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20652 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20654 values[f.name] = v;
20656 var record = new recordType(values, id);
20658 records[records.length] = record;
20662 totalRecords : records.length
20667 * Ext JS Library 1.1.1
20668 * Copyright(c) 2006-2007, Ext JS, LLC.
20670 * Originally Released Under LGPL - original licence link has changed is not relivant.
20673 * <script type="text/javascript">
20678 * @class Roo.data.Tree
20679 * @extends Roo.util.Observable
20680 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20681 * in the tree have most standard DOM functionality.
20683 * @param {Node} root (optional) The root node
20685 Roo.data.Tree = function(root){
20686 this.nodeHash = {};
20688 * The root node for this tree
20693 this.setRootNode(root);
20698 * Fires when a new child node is appended to a node in this tree.
20699 * @param {Tree} tree The owner tree
20700 * @param {Node} parent The parent node
20701 * @param {Node} node The newly appended node
20702 * @param {Number} index The index of the newly appended node
20707 * Fires when a child node is removed from a node in this tree.
20708 * @param {Tree} tree The owner tree
20709 * @param {Node} parent The parent node
20710 * @param {Node} node The child node removed
20715 * Fires when a node is moved to a new location in the tree
20716 * @param {Tree} tree The owner tree
20717 * @param {Node} node The node moved
20718 * @param {Node} oldParent The old parent of this node
20719 * @param {Node} newParent The new parent of this node
20720 * @param {Number} index The index it was moved to
20725 * Fires when a new child node is inserted in a node in this tree.
20726 * @param {Tree} tree The owner tree
20727 * @param {Node} parent The parent node
20728 * @param {Node} node The child node inserted
20729 * @param {Node} refNode The child node the node was inserted before
20733 * @event beforeappend
20734 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20735 * @param {Tree} tree The owner tree
20736 * @param {Node} parent The parent node
20737 * @param {Node} node The child node to be appended
20739 "beforeappend" : true,
20741 * @event beforeremove
20742 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20743 * @param {Tree} tree The owner tree
20744 * @param {Node} parent The parent node
20745 * @param {Node} node The child node to be removed
20747 "beforeremove" : true,
20749 * @event beforemove
20750 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20751 * @param {Tree} tree The owner tree
20752 * @param {Node} node The node being moved
20753 * @param {Node} oldParent The parent of the node
20754 * @param {Node} newParent The new parent the node is moving to
20755 * @param {Number} index The index it is being moved to
20757 "beforemove" : true,
20759 * @event beforeinsert
20760 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20761 * @param {Tree} tree The owner tree
20762 * @param {Node} parent The parent node
20763 * @param {Node} node The child node to be inserted
20764 * @param {Node} refNode The child node the node is being inserted before
20766 "beforeinsert" : true
20769 Roo.data.Tree.superclass.constructor.call(this);
20772 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20773 pathSeparator: "/",
20775 proxyNodeEvent : function(){
20776 return this.fireEvent.apply(this, arguments);
20780 * Returns the root node for this tree.
20783 getRootNode : function(){
20788 * Sets the root node for this tree.
20789 * @param {Node} node
20792 setRootNode : function(node){
20794 node.ownerTree = this;
20795 node.isRoot = true;
20796 this.registerNode(node);
20801 * Gets a node in this tree by its id.
20802 * @param {String} id
20805 getNodeById : function(id){
20806 return this.nodeHash[id];
20809 registerNode : function(node){
20810 this.nodeHash[node.id] = node;
20813 unregisterNode : function(node){
20814 delete this.nodeHash[node.id];
20817 toString : function(){
20818 return "[Tree"+(this.id?" "+this.id:"")+"]";
20823 * @class Roo.data.Node
20824 * @extends Roo.util.Observable
20825 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
20826 * @cfg {String} id The id for this node. If one is not specified, one is generated.
20828 * @param {Object} attributes The attributes/config for the node
20830 Roo.data.Node = function(attributes){
20832 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
20835 this.attributes = attributes || {};
20836 this.leaf = this.attributes.leaf;
20838 * The node id. @type String
20840 this.id = this.attributes.id;
20842 this.id = Roo.id(null, "ynode-");
20843 this.attributes.id = this.id;
20846 * All child nodes of this node. @type Array
20848 this.childNodes = [];
20849 if(!this.childNodes.indexOf){ // indexOf is a must
20850 this.childNodes.indexOf = function(o){
20851 for(var i = 0, len = this.length; i < len; i++){
20852 if(this[i] == o) return i;
20858 * The parent node for this node. @type Node
20860 this.parentNode = null;
20862 * The first direct child node of this node, or null if this node has no child nodes. @type Node
20864 this.firstChild = null;
20866 * The last direct child node of this node, or null if this node has no child nodes. @type Node
20868 this.lastChild = null;
20870 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
20872 this.previousSibling = null;
20874 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
20876 this.nextSibling = null;
20881 * Fires when a new child node is appended
20882 * @param {Tree} tree The owner tree
20883 * @param {Node} this This node
20884 * @param {Node} node The newly appended node
20885 * @param {Number} index The index of the newly appended node
20890 * Fires when a child node is removed
20891 * @param {Tree} tree The owner tree
20892 * @param {Node} this This node
20893 * @param {Node} node The removed node
20898 * Fires when this node is moved to a new location in the tree
20899 * @param {Tree} tree The owner tree
20900 * @param {Node} this This node
20901 * @param {Node} oldParent The old parent of this node
20902 * @param {Node} newParent The new parent of this node
20903 * @param {Number} index The index it was moved to
20908 * Fires when a new child node is inserted.
20909 * @param {Tree} tree The owner tree
20910 * @param {Node} this This node
20911 * @param {Node} node The child node inserted
20912 * @param {Node} refNode The child node the node was inserted before
20916 * @event beforeappend
20917 * Fires before a new child is appended, return false to cancel the append.
20918 * @param {Tree} tree The owner tree
20919 * @param {Node} this This node
20920 * @param {Node} node The child node to be appended
20922 "beforeappend" : true,
20924 * @event beforeremove
20925 * Fires before a child is removed, return false to cancel the remove.
20926 * @param {Tree} tree The owner tree
20927 * @param {Node} this This node
20928 * @param {Node} node The child node to be removed
20930 "beforeremove" : true,
20932 * @event beforemove
20933 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
20934 * @param {Tree} tree The owner tree
20935 * @param {Node} this This node
20936 * @param {Node} oldParent The parent of this node
20937 * @param {Node} newParent The new parent this node is moving to
20938 * @param {Number} index The index it is being moved to
20940 "beforemove" : true,
20942 * @event beforeinsert
20943 * Fires before a new child is inserted, return false to cancel the insert.
20944 * @param {Tree} tree The owner tree
20945 * @param {Node} this This node
20946 * @param {Node} node The child node to be inserted
20947 * @param {Node} refNode The child node the node is being inserted before
20949 "beforeinsert" : true
20951 this.listeners = this.attributes.listeners;
20952 Roo.data.Node.superclass.constructor.call(this);
20955 Roo.extend(Roo.data.Node, Roo.util.Observable, {
20956 fireEvent : function(evtName){
20957 // first do standard event for this node
20958 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
20961 // then bubble it up to the tree if the event wasn't cancelled
20962 var ot = this.getOwnerTree();
20964 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
20972 * Returns true if this node is a leaf
20973 * @return {Boolean}
20975 isLeaf : function(){
20976 return this.leaf === true;
20980 setFirstChild : function(node){
20981 this.firstChild = node;
20985 setLastChild : function(node){
20986 this.lastChild = node;
20991 * Returns true if this node is the last child of its parent
20992 * @return {Boolean}
20994 isLast : function(){
20995 return (!this.parentNode ? true : this.parentNode.lastChild == this);
20999 * Returns true if this node is the first child of its parent
21000 * @return {Boolean}
21002 isFirst : function(){
21003 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21006 hasChildNodes : function(){
21007 return !this.isLeaf() && this.childNodes.length > 0;
21011 * Insert node(s) as the last child node of this node.
21012 * @param {Node/Array} node The node or Array of nodes to append
21013 * @return {Node} The appended node if single append, or null if an array was passed
21015 appendChild : function(node){
21017 if(node instanceof Array){
21019 }else if(arguments.length > 1){
21022 // if passed an array or multiple args do them one by one
21024 for(var i = 0, len = multi.length; i < len; i++) {
21025 this.appendChild(multi[i]);
21028 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21031 var index = this.childNodes.length;
21032 var oldParent = node.parentNode;
21033 // it's a move, make sure we move it cleanly
21035 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21038 oldParent.removeChild(node);
21040 index = this.childNodes.length;
21042 this.setFirstChild(node);
21044 this.childNodes.push(node);
21045 node.parentNode = this;
21046 var ps = this.childNodes[index-1];
21048 node.previousSibling = ps;
21049 ps.nextSibling = node;
21051 node.previousSibling = null;
21053 node.nextSibling = null;
21054 this.setLastChild(node);
21055 node.setOwnerTree(this.getOwnerTree());
21056 this.fireEvent("append", this.ownerTree, this, node, index);
21058 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21065 * Removes a child node from this node.
21066 * @param {Node} node The node to remove
21067 * @return {Node} The removed node
21069 removeChild : function(node){
21070 var index = this.childNodes.indexOf(node);
21074 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21078 // remove it from childNodes collection
21079 this.childNodes.splice(index, 1);
21082 if(node.previousSibling){
21083 node.previousSibling.nextSibling = node.nextSibling;
21085 if(node.nextSibling){
21086 node.nextSibling.previousSibling = node.previousSibling;
21089 // update child refs
21090 if(this.firstChild == node){
21091 this.setFirstChild(node.nextSibling);
21093 if(this.lastChild == node){
21094 this.setLastChild(node.previousSibling);
21097 node.setOwnerTree(null);
21098 // clear any references from the node
21099 node.parentNode = null;
21100 node.previousSibling = null;
21101 node.nextSibling = null;
21102 this.fireEvent("remove", this.ownerTree, this, node);
21107 * Inserts the first node before the second node in this nodes childNodes collection.
21108 * @param {Node} node The node to insert
21109 * @param {Node} refNode The node to insert before (if null the node is appended)
21110 * @return {Node} The inserted node
21112 insertBefore : function(node, refNode){
21113 if(!refNode){ // like standard Dom, refNode can be null for append
21114 return this.appendChild(node);
21117 if(node == refNode){
21121 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21124 var index = this.childNodes.indexOf(refNode);
21125 var oldParent = node.parentNode;
21126 var refIndex = index;
21128 // when moving internally, indexes will change after remove
21129 if(oldParent == this && this.childNodes.indexOf(node) < index){
21133 // it's a move, make sure we move it cleanly
21135 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21138 oldParent.removeChild(node);
21141 this.setFirstChild(node);
21143 this.childNodes.splice(refIndex, 0, node);
21144 node.parentNode = this;
21145 var ps = this.childNodes[refIndex-1];
21147 node.previousSibling = ps;
21148 ps.nextSibling = node;
21150 node.previousSibling = null;
21152 node.nextSibling = refNode;
21153 refNode.previousSibling = node;
21154 node.setOwnerTree(this.getOwnerTree());
21155 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21157 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21163 * Returns the child node at the specified index.
21164 * @param {Number} index
21167 item : function(index){
21168 return this.childNodes[index];
21172 * Replaces one child node in this node with another.
21173 * @param {Node} newChild The replacement node
21174 * @param {Node} oldChild The node to replace
21175 * @return {Node} The replaced node
21177 replaceChild : function(newChild, oldChild){
21178 this.insertBefore(newChild, oldChild);
21179 this.removeChild(oldChild);
21184 * Returns the index of a child node
21185 * @param {Node} node
21186 * @return {Number} The index of the node or -1 if it was not found
21188 indexOf : function(child){
21189 return this.childNodes.indexOf(child);
21193 * Returns the tree this node is in.
21196 getOwnerTree : function(){
21197 // if it doesn't have one, look for one
21198 if(!this.ownerTree){
21202 this.ownerTree = p.ownerTree;
21208 return this.ownerTree;
21212 * Returns depth of this node (the root node has a depth of 0)
21215 getDepth : function(){
21218 while(p.parentNode){
21226 setOwnerTree : function(tree){
21227 // if it's move, we need to update everyone
21228 if(tree != this.ownerTree){
21229 if(this.ownerTree){
21230 this.ownerTree.unregisterNode(this);
21232 this.ownerTree = tree;
21233 var cs = this.childNodes;
21234 for(var i = 0, len = cs.length; i < len; i++) {
21235 cs[i].setOwnerTree(tree);
21238 tree.registerNode(this);
21244 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21245 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21246 * @return {String} The path
21248 getPath : function(attr){
21249 attr = attr || "id";
21250 var p = this.parentNode;
21251 var b = [this.attributes[attr]];
21253 b.unshift(p.attributes[attr]);
21256 var sep = this.getOwnerTree().pathSeparator;
21257 return sep + b.join(sep);
21261 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21262 * function call will be the scope provided or the current node. The arguments to the function
21263 * will be the args provided or the current node. If the function returns false at any point,
21264 * the bubble is stopped.
21265 * @param {Function} fn The function to call
21266 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21267 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21269 bubble : function(fn, scope, args){
21272 if(fn.call(scope || p, args || p) === false){
21280 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21281 * function call will be the scope provided or the current node. The arguments to the function
21282 * will be the args provided or the current node. If the function returns false at any point,
21283 * the cascade is stopped on that branch.
21284 * @param {Function} fn The function to call
21285 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21286 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21288 cascade : function(fn, scope, args){
21289 if(fn.call(scope || this, args || this) !== false){
21290 var cs = this.childNodes;
21291 for(var i = 0, len = cs.length; i < len; i++) {
21292 cs[i].cascade(fn, scope, args);
21298 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21299 * function call will be the scope provided or the current node. The arguments to the function
21300 * will be the args provided or the current node. If the function returns false at any point,
21301 * the iteration stops.
21302 * @param {Function} fn The function to call
21303 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21304 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21306 eachChild : function(fn, scope, args){
21307 var cs = this.childNodes;
21308 for(var i = 0, len = cs.length; i < len; i++) {
21309 if(fn.call(scope || this, args || cs[i]) === false){
21316 * Finds the first child that has the attribute with the specified value.
21317 * @param {String} attribute The attribute name
21318 * @param {Mixed} value The value to search for
21319 * @return {Node} The found child or null if none was found
21321 findChild : function(attribute, value){
21322 var cs = this.childNodes;
21323 for(var i = 0, len = cs.length; i < len; i++) {
21324 if(cs[i].attributes[attribute] == value){
21332 * Finds the first child by a custom function. The child matches if the function passed
21334 * @param {Function} fn
21335 * @param {Object} scope (optional)
21336 * @return {Node} The found child or null if none was found
21338 findChildBy : function(fn, scope){
21339 var cs = this.childNodes;
21340 for(var i = 0, len = cs.length; i < len; i++) {
21341 if(fn.call(scope||cs[i], cs[i]) === true){
21349 * Sorts this nodes children using the supplied sort function
21350 * @param {Function} fn
21351 * @param {Object} scope (optional)
21353 sort : function(fn, scope){
21354 var cs = this.childNodes;
21355 var len = cs.length;
21357 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21359 for(var i = 0; i < len; i++){
21361 n.previousSibling = cs[i-1];
21362 n.nextSibling = cs[i+1];
21364 this.setFirstChild(n);
21367 this.setLastChild(n);
21374 * Returns true if this node is an ancestor (at any point) of the passed node.
21375 * @param {Node} node
21376 * @return {Boolean}
21378 contains : function(node){
21379 return node.isAncestor(this);
21383 * Returns true if the passed node is an ancestor (at any point) of this node.
21384 * @param {Node} node
21385 * @return {Boolean}
21387 isAncestor : function(node){
21388 var p = this.parentNode;
21398 toString : function(){
21399 return "[Node"+(this.id?" "+this.id:"")+"]";
21403 * Ext JS Library 1.1.1
21404 * Copyright(c) 2006-2007, Ext JS, LLC.
21406 * Originally Released Under LGPL - original licence link has changed is not relivant.
21409 * <script type="text/javascript">
21414 * @class Roo.ComponentMgr
21415 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21418 Roo.ComponentMgr = function(){
21419 var all = new Roo.util.MixedCollection();
21423 * Registers a component.
21424 * @param {Roo.Component} c The component
21426 register : function(c){
21431 * Unregisters a component.
21432 * @param {Roo.Component} c The component
21434 unregister : function(c){
21439 * Returns a component by id
21440 * @param {String} id The component id
21442 get : function(id){
21443 return all.get(id);
21447 * Registers a function that will be called when a specified component is added to ComponentMgr
21448 * @param {String} id The component id
21449 * @param {Funtction} fn The callback function
21450 * @param {Object} scope The scope of the callback
21452 onAvailable : function(id, fn, scope){
21453 all.on("add", function(index, o){
21455 fn.call(scope || o, o);
21456 all.un("add", fn, scope);
21463 * Ext JS Library 1.1.1
21464 * Copyright(c) 2006-2007, Ext JS, LLC.
21466 * Originally Released Under LGPL - original licence link has changed is not relivant.
21469 * <script type="text/javascript">
21473 * @class Roo.Component
21474 * @extends Roo.util.Observable
21475 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21476 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21477 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21478 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21479 * All visual components (widgets) that require rendering into a layout should subclass Component.
21481 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21482 * 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
21483 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21485 Roo.Component = function(config){
21486 config = config || {};
21487 if(config.tagName || config.dom || typeof config == "string"){ // element object
21488 config = {el: config, id: config.id || config};
21490 this.initialConfig = config;
21492 Roo.apply(this, config);
21496 * Fires after the component is disabled.
21497 * @param {Roo.Component} this
21502 * Fires after the component is enabled.
21503 * @param {Roo.Component} this
21507 * @event beforeshow
21508 * Fires before the component is shown. Return false to stop the show.
21509 * @param {Roo.Component} this
21514 * Fires after the component is shown.
21515 * @param {Roo.Component} this
21519 * @event beforehide
21520 * Fires before the component is hidden. Return false to stop the hide.
21521 * @param {Roo.Component} this
21526 * Fires after the component is hidden.
21527 * @param {Roo.Component} this
21531 * @event beforerender
21532 * Fires before the component is rendered. Return false to stop the render.
21533 * @param {Roo.Component} this
21535 beforerender : true,
21538 * Fires after the component is rendered.
21539 * @param {Roo.Component} this
21543 * @event beforedestroy
21544 * Fires before the component is destroyed. Return false to stop the destroy.
21545 * @param {Roo.Component} this
21547 beforedestroy : true,
21550 * Fires after the component is destroyed.
21551 * @param {Roo.Component} this
21556 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21558 Roo.ComponentMgr.register(this);
21559 Roo.Component.superclass.constructor.call(this);
21560 this.initComponent();
21561 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21562 this.render(this.renderTo);
21563 delete this.renderTo;
21568 Roo.Component.AUTO_ID = 1000;
21570 Roo.extend(Roo.Component, Roo.util.Observable, {
21572 * @property {Boolean} hidden
21573 * true if this component is hidden. Read-only.
21577 * true if this component is disabled. Read-only.
21581 * true if this component has been rendered. Read-only.
21585 /** @cfg {String} disableClass
21586 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21588 disabledClass : "x-item-disabled",
21589 /** @cfg {Boolean} allowDomMove
21590 * Whether the component can move the Dom node when rendering (defaults to true).
21592 allowDomMove : true,
21593 /** @cfg {String} hideMode
21594 * How this component should hidden. Supported values are
21595 * "visibility" (css visibility), "offsets" (negative offset position) and
21596 * "display" (css display) - defaults to "display".
21598 hideMode: 'display',
21601 ctype : "Roo.Component",
21603 /** @cfg {String} actionMode
21604 * which property holds the element that used for hide() / show() / disable() / enable()
21610 getActionEl : function(){
21611 return this[this.actionMode];
21614 initComponent : Roo.emptyFn,
21616 * If this is a lazy rendering component, render it to its container element.
21617 * @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.
21619 render : function(container, position){
21620 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21621 if(!container && this.el){
21622 this.el = Roo.get(this.el);
21623 container = this.el.dom.parentNode;
21624 this.allowDomMove = false;
21626 this.container = Roo.get(container);
21627 this.rendered = true;
21628 if(position !== undefined){
21629 if(typeof position == 'number'){
21630 position = this.container.dom.childNodes[position];
21632 position = Roo.getDom(position);
21635 this.onRender(this.container, position || null);
21637 this.el.addClass(this.cls);
21641 this.el.applyStyles(this.style);
21644 this.fireEvent("render", this);
21645 this.afterRender(this.container);
21657 // default function is not really useful
21658 onRender : function(ct, position){
21660 this.el = Roo.get(this.el);
21661 if(this.allowDomMove !== false){
21662 ct.dom.insertBefore(this.el.dom, position);
21668 getAutoCreate : function(){
21669 var cfg = typeof this.autoCreate == "object" ?
21670 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21671 if(this.id && !cfg.id){
21678 afterRender : Roo.emptyFn,
21681 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21682 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21684 destroy : function(){
21685 if(this.fireEvent("beforedestroy", this) !== false){
21686 this.purgeListeners();
21687 this.beforeDestroy();
21689 this.el.removeAllListeners();
21691 if(this.actionMode == "container"){
21692 this.container.remove();
21696 Roo.ComponentMgr.unregister(this);
21697 this.fireEvent("destroy", this);
21702 beforeDestroy : function(){
21707 onDestroy : function(){
21712 * Returns the underlying {@link Roo.Element}.
21713 * @return {Roo.Element} The element
21715 getEl : function(){
21720 * Returns the id of this component.
21723 getId : function(){
21728 * Try to focus this component.
21729 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21730 * @return {Roo.Component} this
21732 focus : function(selectText){
21735 if(selectText === true){
21736 this.el.dom.select();
21751 * Disable this component.
21752 * @return {Roo.Component} this
21754 disable : function(){
21758 this.disabled = true;
21759 this.fireEvent("disable", this);
21764 onDisable : function(){
21765 this.getActionEl().addClass(this.disabledClass);
21766 this.el.dom.disabled = true;
21770 * Enable this component.
21771 * @return {Roo.Component} this
21773 enable : function(){
21777 this.disabled = false;
21778 this.fireEvent("enable", this);
21783 onEnable : function(){
21784 this.getActionEl().removeClass(this.disabledClass);
21785 this.el.dom.disabled = false;
21789 * Convenience function for setting disabled/enabled by boolean.
21790 * @param {Boolean} disabled
21792 setDisabled : function(disabled){
21793 this[disabled ? "disable" : "enable"]();
21797 * Show this component.
21798 * @return {Roo.Component} this
21801 if(this.fireEvent("beforeshow", this) !== false){
21802 this.hidden = false;
21806 this.fireEvent("show", this);
21812 onShow : function(){
21813 var ae = this.getActionEl();
21814 if(this.hideMode == 'visibility'){
21815 ae.dom.style.visibility = "visible";
21816 }else if(this.hideMode == 'offsets'){
21817 ae.removeClass('x-hidden');
21819 ae.dom.style.display = "";
21824 * Hide this component.
21825 * @return {Roo.Component} this
21828 if(this.fireEvent("beforehide", this) !== false){
21829 this.hidden = true;
21833 this.fireEvent("hide", this);
21839 onHide : function(){
21840 var ae = this.getActionEl();
21841 if(this.hideMode == 'visibility'){
21842 ae.dom.style.visibility = "hidden";
21843 }else if(this.hideMode == 'offsets'){
21844 ae.addClass('x-hidden');
21846 ae.dom.style.display = "none";
21851 * Convenience function to hide or show this component by boolean.
21852 * @param {Boolean} visible True to show, false to hide
21853 * @return {Roo.Component} this
21855 setVisible: function(visible){
21865 * Returns true if this component is visible.
21867 isVisible : function(){
21868 return this.getActionEl().isVisible();
21871 cloneConfig : function(overrides){
21872 overrides = overrides || {};
21873 var id = overrides.id || Roo.id();
21874 var cfg = Roo.applyIf(overrides, this.initialConfig);
21875 cfg.id = id; // prevent dup id
21876 return new this.constructor(cfg);
21880 * Ext JS Library 1.1.1
21881 * Copyright(c) 2006-2007, Ext JS, LLC.
21883 * Originally Released Under LGPL - original licence link has changed is not relivant.
21886 * <script type="text/javascript">
21891 * @extends Roo.Element
21892 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
21893 * automatic maintaining of shadow/shim positions.
21894 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
21895 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
21896 * you can pass a string with a CSS class name. False turns off the shadow.
21897 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
21898 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
21899 * @cfg {String} cls CSS class to add to the element
21900 * @cfg {Number} zindex Starting z-index (defaults to 11000)
21901 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
21903 * @param {Object} config An object with config options.
21904 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
21907 Roo.Layer = function(config, existingEl){
21908 config = config || {};
21909 var dh = Roo.DomHelper;
21910 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
21912 this.dom = Roo.getDom(existingEl);
21915 var o = config.dh || {tag: "div", cls: "x-layer"};
21916 this.dom = dh.append(pel, o);
21919 this.addClass(config.cls);
21921 this.constrain = config.constrain !== false;
21922 this.visibilityMode = Roo.Element.VISIBILITY;
21924 this.id = this.dom.id = config.id;
21926 this.id = Roo.id(this.dom);
21928 this.zindex = config.zindex || this.getZIndex();
21929 this.position("absolute", this.zindex);
21931 this.shadowOffset = config.shadowOffset || 4;
21932 this.shadow = new Roo.Shadow({
21933 offset : this.shadowOffset,
21934 mode : config.shadow
21937 this.shadowOffset = 0;
21939 this.useShim = config.shim !== false && Roo.useShims;
21940 this.useDisplay = config.useDisplay;
21944 var supr = Roo.Element.prototype;
21946 // shims are shared among layer to keep from having 100 iframes
21949 Roo.extend(Roo.Layer, Roo.Element, {
21951 getZIndex : function(){
21952 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
21955 getShim : function(){
21962 var shim = shims.shift();
21964 shim = this.createShim();
21965 shim.enableDisplayMode('block');
21966 shim.dom.style.display = 'none';
21967 shim.dom.style.visibility = 'visible';
21969 var pn = this.dom.parentNode;
21970 if(shim.dom.parentNode != pn){
21971 pn.insertBefore(shim.dom, this.dom);
21973 shim.setStyle('z-index', this.getZIndex()-2);
21978 hideShim : function(){
21980 this.shim.setDisplayed(false);
21981 shims.push(this.shim);
21986 disableShadow : function(){
21988 this.shadowDisabled = true;
21989 this.shadow.hide();
21990 this.lastShadowOffset = this.shadowOffset;
21991 this.shadowOffset = 0;
21995 enableShadow : function(show){
21997 this.shadowDisabled = false;
21998 this.shadowOffset = this.lastShadowOffset;
21999 delete this.lastShadowOffset;
22007 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22008 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22009 sync : function(doShow){
22010 var sw = this.shadow;
22011 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22012 var sh = this.getShim();
22014 var w = this.getWidth(),
22015 h = this.getHeight();
22017 var l = this.getLeft(true),
22018 t = this.getTop(true);
22020 if(sw && !this.shadowDisabled){
22021 if(doShow && !sw.isVisible()){
22024 sw.realign(l, t, w, h);
22030 // fit the shim behind the shadow, so it is shimmed too
22031 var a = sw.adjusts, s = sh.dom.style;
22032 s.left = (Math.min(l, l+a.l))+"px";
22033 s.top = (Math.min(t, t+a.t))+"px";
22034 s.width = (w+a.w)+"px";
22035 s.height = (h+a.h)+"px";
22042 sh.setLeftTop(l, t);
22049 destroy : function(){
22052 this.shadow.hide();
22054 this.removeAllListeners();
22055 var pn = this.dom.parentNode;
22057 pn.removeChild(this.dom);
22059 Roo.Element.uncache(this.id);
22062 remove : function(){
22067 beginUpdate : function(){
22068 this.updating = true;
22072 endUpdate : function(){
22073 this.updating = false;
22078 hideUnders : function(negOffset){
22080 this.shadow.hide();
22086 constrainXY : function(){
22087 if(this.constrain){
22088 var vw = Roo.lib.Dom.getViewWidth(),
22089 vh = Roo.lib.Dom.getViewHeight();
22090 var s = Roo.get(document).getScroll();
22092 var xy = this.getXY();
22093 var x = xy[0], y = xy[1];
22094 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22095 // only move it if it needs it
22097 // first validate right/bottom
22098 if((x + w) > vw+s.left){
22099 x = vw - w - this.shadowOffset;
22102 if((y + h) > vh+s.top){
22103 y = vh - h - this.shadowOffset;
22106 // then make sure top/left isn't negative
22117 var ay = this.avoidY;
22118 if(y <= ay && (y+h) >= ay){
22124 supr.setXY.call(this, xy);
22130 isVisible : function(){
22131 return this.visible;
22135 showAction : function(){
22136 this.visible = true; // track visibility to prevent getStyle calls
22137 if(this.useDisplay === true){
22138 this.setDisplayed("");
22139 }else if(this.lastXY){
22140 supr.setXY.call(this, this.lastXY);
22141 }else if(this.lastLT){
22142 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22147 hideAction : function(){
22148 this.visible = false;
22149 if(this.useDisplay === true){
22150 this.setDisplayed(false);
22152 this.setLeftTop(-10000,-10000);
22156 // overridden Element method
22157 setVisible : function(v, a, d, c, e){
22162 var cb = function(){
22167 }.createDelegate(this);
22168 supr.setVisible.call(this, true, true, d, cb, e);
22171 this.hideUnders(true);
22180 }.createDelegate(this);
22182 supr.setVisible.call(this, v, a, d, cb, e);
22191 storeXY : function(xy){
22192 delete this.lastLT;
22196 storeLeftTop : function(left, top){
22197 delete this.lastXY;
22198 this.lastLT = [left, top];
22202 beforeFx : function(){
22203 this.beforeAction();
22204 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22208 afterFx : function(){
22209 Roo.Layer.superclass.afterFx.apply(this, arguments);
22210 this.sync(this.isVisible());
22214 beforeAction : function(){
22215 if(!this.updating && this.shadow){
22216 this.shadow.hide();
22220 // overridden Element method
22221 setLeft : function(left){
22222 this.storeLeftTop(left, this.getTop(true));
22223 supr.setLeft.apply(this, arguments);
22227 setTop : function(top){
22228 this.storeLeftTop(this.getLeft(true), top);
22229 supr.setTop.apply(this, arguments);
22233 setLeftTop : function(left, top){
22234 this.storeLeftTop(left, top);
22235 supr.setLeftTop.apply(this, arguments);
22239 setXY : function(xy, a, d, c, e){
22241 this.beforeAction();
22243 var cb = this.createCB(c);
22244 supr.setXY.call(this, xy, a, d, cb, e);
22251 createCB : function(c){
22262 // overridden Element method
22263 setX : function(x, a, d, c, e){
22264 this.setXY([x, this.getY()], a, d, c, e);
22267 // overridden Element method
22268 setY : function(y, a, d, c, e){
22269 this.setXY([this.getX(), y], a, d, c, e);
22272 // overridden Element method
22273 setSize : function(w, h, a, d, c, e){
22274 this.beforeAction();
22275 var cb = this.createCB(c);
22276 supr.setSize.call(this, w, h, a, d, cb, e);
22282 // overridden Element method
22283 setWidth : function(w, a, d, c, e){
22284 this.beforeAction();
22285 var cb = this.createCB(c);
22286 supr.setWidth.call(this, w, a, d, cb, e);
22292 // overridden Element method
22293 setHeight : function(h, a, d, c, e){
22294 this.beforeAction();
22295 var cb = this.createCB(c);
22296 supr.setHeight.call(this, h, a, d, cb, e);
22302 // overridden Element method
22303 setBounds : function(x, y, w, h, a, d, c, e){
22304 this.beforeAction();
22305 var cb = this.createCB(c);
22307 this.storeXY([x, y]);
22308 supr.setXY.call(this, [x, y]);
22309 supr.setSize.call(this, w, h, a, d, cb, e);
22312 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22318 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22319 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22320 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22321 * @param {Number} zindex The new z-index to set
22322 * @return {this} The Layer
22324 setZIndex : function(zindex){
22325 this.zindex = zindex;
22326 this.setStyle("z-index", zindex + 2);
22328 this.shadow.setZIndex(zindex + 1);
22331 this.shim.setStyle("z-index", zindex);
22337 * Ext JS Library 1.1.1
22338 * Copyright(c) 2006-2007, Ext JS, LLC.
22340 * Originally Released Under LGPL - original licence link has changed is not relivant.
22343 * <script type="text/javascript">
22348 * @class Roo.Shadow
22349 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22350 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22351 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22353 * Create a new Shadow
22354 * @param {Object} config The config object
22356 Roo.Shadow = function(config){
22357 Roo.apply(this, config);
22358 if(typeof this.mode != "string"){
22359 this.mode = this.defaultMode;
22361 var o = this.offset, a = {h: 0};
22362 var rad = Math.floor(this.offset/2);
22363 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22369 a.l -= this.offset + rad;
22370 a.t -= this.offset + rad;
22381 a.l -= (this.offset - rad);
22382 a.t -= this.offset + rad;
22384 a.w -= (this.offset - rad)*2;
22395 a.l -= (this.offset - rad);
22396 a.t -= (this.offset - rad);
22398 a.w -= (this.offset + rad + 1);
22399 a.h -= (this.offset + rad);
22408 Roo.Shadow.prototype = {
22410 * @cfg {String} mode
22411 * The shadow display mode. Supports the following options:<br />
22412 * sides: Shadow displays on both sides and bottom only<br />
22413 * frame: Shadow displays equally on all four sides<br />
22414 * drop: Traditional bottom-right drop shadow (default)
22417 * @cfg {String} offset
22418 * The number of pixels to offset the shadow from the element (defaults to 4)
22423 defaultMode: "drop",
22426 * Displays the shadow under the target element
22427 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22429 show : function(target){
22430 target = Roo.get(target);
22432 this.el = Roo.Shadow.Pool.pull();
22433 if(this.el.dom.nextSibling != target.dom){
22434 this.el.insertBefore(target);
22437 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22439 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22442 target.getLeft(true),
22443 target.getTop(true),
22447 this.el.dom.style.display = "block";
22451 * Returns true if the shadow is visible, else false
22453 isVisible : function(){
22454 return this.el ? true : false;
22458 * Direct alignment when values are already available. Show must be called at least once before
22459 * calling this method to ensure it is initialized.
22460 * @param {Number} left The target element left position
22461 * @param {Number} top The target element top position
22462 * @param {Number} width The target element width
22463 * @param {Number} height The target element height
22465 realign : function(l, t, w, h){
22469 var a = this.adjusts, d = this.el.dom, s = d.style;
22471 s.left = (l+a.l)+"px";
22472 s.top = (t+a.t)+"px";
22473 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22474 if(s.width != sws || s.height != shs){
22478 var cn = d.childNodes;
22479 var sww = Math.max(0, (sw-12))+"px";
22480 cn[0].childNodes[1].style.width = sww;
22481 cn[1].childNodes[1].style.width = sww;
22482 cn[2].childNodes[1].style.width = sww;
22483 cn[1].style.height = Math.max(0, (sh-12))+"px";
22489 * Hides this shadow
22493 this.el.dom.style.display = "none";
22494 Roo.Shadow.Pool.push(this.el);
22500 * Adjust the z-index of this shadow
22501 * @param {Number} zindex The new z-index
22503 setZIndex : function(z){
22506 this.el.setStyle("z-index", z);
22511 // Private utility class that manages the internal Shadow cache
22512 Roo.Shadow.Pool = function(){
22514 var markup = Roo.isIE ?
22515 '<div class="x-ie-shadow"></div>' :
22516 '<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>';
22519 var sh = p.shift();
22521 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22522 sh.autoBoxAdjust = false;
22527 push : function(sh){
22533 * Ext JS Library 1.1.1
22534 * Copyright(c) 2006-2007, Ext JS, LLC.
22536 * Originally Released Under LGPL - original licence link has changed is not relivant.
22539 * <script type="text/javascript">
22543 * @class Roo.BoxComponent
22544 * @extends Roo.Component
22545 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22546 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22547 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22548 * layout containers.
22550 * @param {Roo.Element/String/Object} config The configuration options.
22552 Roo.BoxComponent = function(config){
22553 Roo.Component.call(this, config);
22557 * Fires after the component is resized.
22558 * @param {Roo.Component} this
22559 * @param {Number} adjWidth The box-adjusted width that was set
22560 * @param {Number} adjHeight The box-adjusted height that was set
22561 * @param {Number} rawWidth The width that was originally specified
22562 * @param {Number} rawHeight The height that was originally specified
22567 * Fires after the component is moved.
22568 * @param {Roo.Component} this
22569 * @param {Number} x The new x position
22570 * @param {Number} y The new y position
22576 Roo.extend(Roo.BoxComponent, Roo.Component, {
22577 // private, set in afterRender to signify that the component has been rendered
22579 // private, used to defer height settings to subclasses
22580 deferHeight: false,
22581 /** @cfg {Number} width
22582 * width (optional) size of component
22584 /** @cfg {Number} height
22585 * height (optional) size of component
22589 * Sets the width and height of the component. This method fires the resize event. This method can accept
22590 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22591 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22592 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22593 * @return {Roo.BoxComponent} this
22595 setSize : function(w, h){
22596 // support for standard size objects
22597 if(typeof w == 'object'){
22602 if(!this.boxReady){
22608 // prevent recalcs when not needed
22609 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22612 this.lastSize = {width: w, height: h};
22614 var adj = this.adjustSize(w, h);
22615 var aw = adj.width, ah = adj.height;
22616 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22617 var rz = this.getResizeEl();
22618 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22619 rz.setSize(aw, ah);
22620 }else if(!this.deferHeight && ah !== undefined){
22622 }else if(aw !== undefined){
22625 this.onResize(aw, ah, w, h);
22626 this.fireEvent('resize', this, aw, ah, w, h);
22632 * Gets the current size of the component's underlying element.
22633 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22635 getSize : function(){
22636 return this.el.getSize();
22640 * Gets the current XY position of the component's underlying element.
22641 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22642 * @return {Array} The XY position of the element (e.g., [100, 200])
22644 getPosition : function(local){
22645 if(local === true){
22646 return [this.el.getLeft(true), this.el.getTop(true)];
22648 return this.xy || this.el.getXY();
22652 * Gets the current box measurements of the component's underlying element.
22653 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22654 * @returns {Object} box An object in the format {x, y, width, height}
22656 getBox : function(local){
22657 var s = this.el.getSize();
22659 s.x = this.el.getLeft(true);
22660 s.y = this.el.getTop(true);
22662 var xy = this.xy || this.el.getXY();
22670 * Sets the current box measurements of the component's underlying element.
22671 * @param {Object} box An object in the format {x, y, width, height}
22672 * @returns {Roo.BoxComponent} this
22674 updateBox : function(box){
22675 this.setSize(box.width, box.height);
22676 this.setPagePosition(box.x, box.y);
22681 getResizeEl : function(){
22682 return this.resizeEl || this.el;
22686 getPositionEl : function(){
22687 return this.positionEl || this.el;
22691 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22692 * This method fires the move event.
22693 * @param {Number} left The new left
22694 * @param {Number} top The new top
22695 * @returns {Roo.BoxComponent} this
22697 setPosition : function(x, y){
22700 if(!this.boxReady){
22703 var adj = this.adjustPosition(x, y);
22704 var ax = adj.x, ay = adj.y;
22706 var el = this.getPositionEl();
22707 if(ax !== undefined || ay !== undefined){
22708 if(ax !== undefined && ay !== undefined){
22709 el.setLeftTop(ax, ay);
22710 }else if(ax !== undefined){
22712 }else if(ay !== undefined){
22715 this.onPosition(ax, ay);
22716 this.fireEvent('move', this, ax, ay);
22722 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22723 * This method fires the move event.
22724 * @param {Number} x The new x position
22725 * @param {Number} y The new y position
22726 * @returns {Roo.BoxComponent} this
22728 setPagePosition : function(x, y){
22731 if(!this.boxReady){
22734 if(x === undefined || y === undefined){ // cannot translate undefined points
22737 var p = this.el.translatePoints(x, y);
22738 this.setPosition(p.left, p.top);
22743 onRender : function(ct, position){
22744 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22746 this.resizeEl = Roo.get(this.resizeEl);
22748 if(this.positionEl){
22749 this.positionEl = Roo.get(this.positionEl);
22754 afterRender : function(){
22755 Roo.BoxComponent.superclass.afterRender.call(this);
22756 this.boxReady = true;
22757 this.setSize(this.width, this.height);
22758 if(this.x || this.y){
22759 this.setPosition(this.x, this.y);
22761 if(this.pageX || this.pageY){
22762 this.setPagePosition(this.pageX, this.pageY);
22767 * Force the component's size to recalculate based on the underlying element's current height and width.
22768 * @returns {Roo.BoxComponent} this
22770 syncSize : function(){
22771 delete this.lastSize;
22772 this.setSize(this.el.getWidth(), this.el.getHeight());
22777 * Called after the component is resized, this method is empty by default but can be implemented by any
22778 * subclass that needs to perform custom logic after a resize occurs.
22779 * @param {Number} adjWidth The box-adjusted width that was set
22780 * @param {Number} adjHeight The box-adjusted height that was set
22781 * @param {Number} rawWidth The width that was originally specified
22782 * @param {Number} rawHeight The height that was originally specified
22784 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22789 * Called after the component is moved, this method is empty by default but can be implemented by any
22790 * subclass that needs to perform custom logic after a move occurs.
22791 * @param {Number} x The new x position
22792 * @param {Number} y The new y position
22794 onPosition : function(x, y){
22799 adjustSize : function(w, h){
22800 if(this.autoWidth){
22803 if(this.autoHeight){
22806 return {width : w, height: h};
22810 adjustPosition : function(x, y){
22811 return {x : x, y: y};
22815 * Ext JS Library 1.1.1
22816 * Copyright(c) 2006-2007, Ext JS, LLC.
22818 * Originally Released Under LGPL - original licence link has changed is not relivant.
22821 * <script type="text/javascript">
22826 * @class Roo.SplitBar
22827 * @extends Roo.util.Observable
22828 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
22832 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
22833 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
22834 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
22835 split.minSize = 100;
22836 split.maxSize = 600;
22837 split.animate = true;
22838 split.on('moved', splitterMoved);
22841 * Create a new SplitBar
22842 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
22843 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
22844 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22845 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
22846 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
22847 position of the SplitBar).
22849 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
22852 this.el = Roo.get(dragElement, true);
22853 this.el.dom.unselectable = "on";
22855 this.resizingEl = Roo.get(resizingElement, true);
22859 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22860 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
22863 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
22866 * The minimum size of the resizing element. (Defaults to 0)
22872 * The maximum size of the resizing element. (Defaults to 2000)
22875 this.maxSize = 2000;
22878 * Whether to animate the transition to the new size
22881 this.animate = false;
22884 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
22887 this.useShim = false;
22892 if(!existingProxy){
22894 this.proxy = Roo.SplitBar.createProxy(this.orientation);
22896 this.proxy = Roo.get(existingProxy).dom;
22899 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
22902 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
22905 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
22908 this.dragSpecs = {};
22911 * @private The adapter to use to positon and resize elements
22913 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
22914 this.adapter.init(this);
22916 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22918 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
22919 this.el.addClass("x-splitbar-h");
22922 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
22923 this.el.addClass("x-splitbar-v");
22929 * Fires when the splitter is moved (alias for {@link #event-moved})
22930 * @param {Roo.SplitBar} this
22931 * @param {Number} newSize the new width or height
22936 * Fires when the splitter is moved
22937 * @param {Roo.SplitBar} this
22938 * @param {Number} newSize the new width or height
22942 * @event beforeresize
22943 * Fires before the splitter is dragged
22944 * @param {Roo.SplitBar} this
22946 "beforeresize" : true,
22948 "beforeapply" : true
22951 Roo.util.Observable.call(this);
22954 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
22955 onStartProxyDrag : function(x, y){
22956 this.fireEvent("beforeresize", this);
22958 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
22960 o.enableDisplayMode("block");
22961 // all splitbars share the same overlay
22962 Roo.SplitBar.prototype.overlay = o;
22964 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
22965 this.overlay.show();
22966 Roo.get(this.proxy).setDisplayed("block");
22967 var size = this.adapter.getElementSize(this);
22968 this.activeMinSize = this.getMinimumSize();;
22969 this.activeMaxSize = this.getMaximumSize();;
22970 var c1 = size - this.activeMinSize;
22971 var c2 = Math.max(this.activeMaxSize - size, 0);
22972 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22973 this.dd.resetConstraints();
22974 this.dd.setXConstraint(
22975 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
22976 this.placement == Roo.SplitBar.LEFT ? c2 : c1
22978 this.dd.setYConstraint(0, 0);
22980 this.dd.resetConstraints();
22981 this.dd.setXConstraint(0, 0);
22982 this.dd.setYConstraint(
22983 this.placement == Roo.SplitBar.TOP ? c1 : c2,
22984 this.placement == Roo.SplitBar.TOP ? c2 : c1
22987 this.dragSpecs.startSize = size;
22988 this.dragSpecs.startPoint = [x, y];
22989 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
22993 * @private Called after the drag operation by the DDProxy
22995 onEndProxyDrag : function(e){
22996 Roo.get(this.proxy).setDisplayed(false);
22997 var endPoint = Roo.lib.Event.getXY(e);
22999 this.overlay.hide();
23002 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23003 newSize = this.dragSpecs.startSize +
23004 (this.placement == Roo.SplitBar.LEFT ?
23005 endPoint[0] - this.dragSpecs.startPoint[0] :
23006 this.dragSpecs.startPoint[0] - endPoint[0]
23009 newSize = this.dragSpecs.startSize +
23010 (this.placement == Roo.SplitBar.TOP ?
23011 endPoint[1] - this.dragSpecs.startPoint[1] :
23012 this.dragSpecs.startPoint[1] - endPoint[1]
23015 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23016 if(newSize != this.dragSpecs.startSize){
23017 if(this.fireEvent('beforeapply', this, newSize) !== false){
23018 this.adapter.setElementSize(this, newSize);
23019 this.fireEvent("moved", this, newSize);
23020 this.fireEvent("resize", this, newSize);
23026 * Get the adapter this SplitBar uses
23027 * @return The adapter object
23029 getAdapter : function(){
23030 return this.adapter;
23034 * Set the adapter this SplitBar uses
23035 * @param {Object} adapter A SplitBar adapter object
23037 setAdapter : function(adapter){
23038 this.adapter = adapter;
23039 this.adapter.init(this);
23043 * Gets the minimum size for the resizing element
23044 * @return {Number} The minimum size
23046 getMinimumSize : function(){
23047 return this.minSize;
23051 * Sets the minimum size for the resizing element
23052 * @param {Number} minSize The minimum size
23054 setMinimumSize : function(minSize){
23055 this.minSize = minSize;
23059 * Gets the maximum size for the resizing element
23060 * @return {Number} The maximum size
23062 getMaximumSize : function(){
23063 return this.maxSize;
23067 * Sets the maximum size for the resizing element
23068 * @param {Number} maxSize The maximum size
23070 setMaximumSize : function(maxSize){
23071 this.maxSize = maxSize;
23075 * Sets the initialize size for the resizing element
23076 * @param {Number} size The initial size
23078 setCurrentSize : function(size){
23079 var oldAnimate = this.animate;
23080 this.animate = false;
23081 this.adapter.setElementSize(this, size);
23082 this.animate = oldAnimate;
23086 * Destroy this splitbar.
23087 * @param {Boolean} removeEl True to remove the element
23089 destroy : function(removeEl){
23091 this.shim.remove();
23094 this.proxy.parentNode.removeChild(this.proxy);
23102 * @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.
23104 Roo.SplitBar.createProxy = function(dir){
23105 var proxy = new Roo.Element(document.createElement("div"));
23106 proxy.unselectable();
23107 var cls = 'x-splitbar-proxy';
23108 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23109 document.body.appendChild(proxy.dom);
23114 * @class Roo.SplitBar.BasicLayoutAdapter
23115 * Default Adapter. It assumes the splitter and resizing element are not positioned
23116 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23118 Roo.SplitBar.BasicLayoutAdapter = function(){
23121 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23122 // do nothing for now
23123 init : function(s){
23127 * Called before drag operations to get the current size of the resizing element.
23128 * @param {Roo.SplitBar} s The SplitBar using this adapter
23130 getElementSize : function(s){
23131 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23132 return s.resizingEl.getWidth();
23134 return s.resizingEl.getHeight();
23139 * Called after drag operations to set the size of the resizing element.
23140 * @param {Roo.SplitBar} s The SplitBar using this adapter
23141 * @param {Number} newSize The new size to set
23142 * @param {Function} onComplete A function to be invoked when resizing is complete
23144 setElementSize : function(s, newSize, onComplete){
23145 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23147 s.resizingEl.setWidth(newSize);
23149 onComplete(s, newSize);
23152 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23157 s.resizingEl.setHeight(newSize);
23159 onComplete(s, newSize);
23162 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23169 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23170 * @extends Roo.SplitBar.BasicLayoutAdapter
23171 * Adapter that moves the splitter element to align with the resized sizing element.
23172 * Used with an absolute positioned SplitBar.
23173 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23174 * document.body, make sure you assign an id to the body element.
23176 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23177 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23178 this.container = Roo.get(container);
23181 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23182 init : function(s){
23183 this.basic.init(s);
23186 getElementSize : function(s){
23187 return this.basic.getElementSize(s);
23190 setElementSize : function(s, newSize, onComplete){
23191 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23194 moveSplitter : function(s){
23195 var yes = Roo.SplitBar;
23196 switch(s.placement){
23198 s.el.setX(s.resizingEl.getRight());
23201 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23204 s.el.setY(s.resizingEl.getBottom());
23207 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23214 * Orientation constant - Create a vertical SplitBar
23218 Roo.SplitBar.VERTICAL = 1;
23221 * Orientation constant - Create a horizontal SplitBar
23225 Roo.SplitBar.HORIZONTAL = 2;
23228 * Placement constant - The resizing element is to the left of the splitter element
23232 Roo.SplitBar.LEFT = 1;
23235 * Placement constant - The resizing element is to the right of the splitter element
23239 Roo.SplitBar.RIGHT = 2;
23242 * Placement constant - The resizing element is positioned above the splitter element
23246 Roo.SplitBar.TOP = 3;
23249 * Placement constant - The resizing element is positioned under splitter element
23253 Roo.SplitBar.BOTTOM = 4;
23256 * Ext JS Library 1.1.1
23257 * Copyright(c) 2006-2007, Ext JS, LLC.
23259 * Originally Released Under LGPL - original licence link has changed is not relivant.
23262 * <script type="text/javascript">
23267 * @extends Roo.util.Observable
23268 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23269 * This class also supports single and multi selection modes. <br>
23270 * Create a data model bound view:
23272 var store = new Roo.data.Store(...);
23274 var view = new Roo.View({
23276 template : '<div id="{0}">{2} - {1}</div>', // auto create template
23278 singleSelect: true,
23279 selectedClass: "ydataview-selected",
23283 // listen for node click?
23284 view.on("click", function(vw, index, node, e){
23285 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23289 dataModel.load("foobar.xml");
23291 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23293 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23294 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23296 * Note: old style constructor is still suported (container, template, config)
23299 * Create a new View
23300 * @param {Object} config The config object
23303 Roo.View = function(config, depreciated_tpl, depreciated_config){
23305 if (typeof(depreciated_tpl) == 'undefined') {
23306 // new way.. - universal constructor.
23307 Roo.apply(this, config);
23308 this.el = Roo.get(this.el);
23311 this.el = Roo.get(config);
23312 this.tpl = depreciated_tpl;
23313 Roo.apply(this, depreciated_config);
23317 if(typeof(this.tpl) == "string"){
23318 this.tpl = new Roo.Template(this.tpl);
23322 this.tpl.compile();
23329 * @event beforeclick
23330 * Fires before a click is processed. Returns false to cancel the default action.
23331 * @param {Roo.View} this
23332 * @param {Number} index The index of the target node
23333 * @param {HTMLElement} node The target node
23334 * @param {Roo.EventObject} e The raw event object
23336 "beforeclick" : true,
23339 * Fires when a template node is clicked.
23340 * @param {Roo.View} this
23341 * @param {Number} index The index of the target node
23342 * @param {HTMLElement} node The target node
23343 * @param {Roo.EventObject} e The raw event object
23348 * Fires when a template node is double clicked.
23349 * @param {Roo.View} this
23350 * @param {Number} index The index of the target node
23351 * @param {HTMLElement} node The target node
23352 * @param {Roo.EventObject} e The raw event object
23356 * @event contextmenu
23357 * Fires when a template node is right clicked.
23358 * @param {Roo.View} this
23359 * @param {Number} index The index of the target node
23360 * @param {HTMLElement} node The target node
23361 * @param {Roo.EventObject} e The raw event object
23363 "contextmenu" : true,
23365 * @event selectionchange
23366 * Fires when the selected nodes change.
23367 * @param {Roo.View} this
23368 * @param {Array} selections Array of the selected nodes
23370 "selectionchange" : true,
23373 * @event beforeselect
23374 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23375 * @param {Roo.View} this
23376 * @param {HTMLElement} node The node to be selected
23377 * @param {Array} selections Array of currently selected nodes
23379 "beforeselect" : true
23383 "click": this.onClick,
23384 "dblclick": this.onDblClick,
23385 "contextmenu": this.onContextMenu,
23389 this.selections = [];
23391 this.cmp = new Roo.CompositeElementLite([]);
23393 this.store = Roo.factory(this.store, Roo.data);
23394 this.setStore(this.store, true);
23396 Roo.View.superclass.constructor.call(this);
23399 Roo.extend(Roo.View, Roo.util.Observable, {
23402 * @cfg {Roo.data.Store} store Data store to load data from.
23407 * @cfg {String|Roo.Element} el The container element.
23412 * @cfg {String|Roo.Template} tpl The template used by this View
23417 * @cfg {String} selectedClass The css class to add to selected nodes
23419 selectedClass : "x-view-selected",
23421 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23425 * Returns the element this view is bound to.
23426 * @return {Roo.Element}
23428 getEl : function(){
23433 * Refreshes the view.
23435 refresh : function(){
23437 this.clearSelections();
23438 this.el.update("");
23440 var records = this.store.getRange();
23441 if(records.length < 1){
23442 this.el.update(this.emptyText);
23445 for(var i = 0, len = records.length; i < len; i++){
23446 var data = this.prepareData(records[i].data, i, records[i]);
23447 html[html.length] = t.apply(data);
23449 this.el.update(html.join(""));
23450 this.nodes = this.el.dom.childNodes;
23451 this.updateIndexes(0);
23455 * Function to override to reformat the data that is sent to
23456 * the template for each node.
23457 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23458 * a JSON object for an UpdateManager bound view).
23460 prepareData : function(data){
23464 onUpdate : function(ds, record){
23465 this.clearSelections();
23466 var index = this.store.indexOf(record);
23467 var n = this.nodes[index];
23468 this.tpl.insertBefore(n, this.prepareData(record.data));
23469 n.parentNode.removeChild(n);
23470 this.updateIndexes(index, index);
23473 onAdd : function(ds, records, index){
23474 this.clearSelections();
23475 if(this.nodes.length == 0){
23479 var n = this.nodes[index];
23480 for(var i = 0, len = records.length; i < len; i++){
23481 var d = this.prepareData(records[i].data);
23483 this.tpl.insertBefore(n, d);
23485 this.tpl.append(this.el, d);
23488 this.updateIndexes(index);
23491 onRemove : function(ds, record, index){
23492 this.clearSelections();
23493 this.el.dom.removeChild(this.nodes[index]);
23494 this.updateIndexes(index);
23498 * Refresh an individual node.
23499 * @param {Number} index
23501 refreshNode : function(index){
23502 this.onUpdate(this.store, this.store.getAt(index));
23505 updateIndexes : function(startIndex, endIndex){
23506 var ns = this.nodes;
23507 startIndex = startIndex || 0;
23508 endIndex = endIndex || ns.length - 1;
23509 for(var i = startIndex; i <= endIndex; i++){
23510 ns[i].nodeIndex = i;
23515 * Changes the data store this view uses and refresh the view.
23516 * @param {Store} store
23518 setStore : function(store, initial){
23519 if(!initial && this.store){
23520 this.store.un("datachanged", this.refresh);
23521 this.store.un("add", this.onAdd);
23522 this.store.un("remove", this.onRemove);
23523 this.store.un("update", this.onUpdate);
23524 this.store.un("clear", this.refresh);
23528 store.on("datachanged", this.refresh, this);
23529 store.on("add", this.onAdd, this);
23530 store.on("remove", this.onRemove, this);
23531 store.on("update", this.onUpdate, this);
23532 store.on("clear", this.refresh, this);
23541 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23542 * @param {HTMLElement} node
23543 * @return {HTMLElement} The template node
23545 findItemFromChild : function(node){
23546 var el = this.el.dom;
23547 if(!node || node.parentNode == el){
23550 var p = node.parentNode;
23551 while(p && p != el){
23552 if(p.parentNode == el){
23561 onClick : function(e){
23562 var item = this.findItemFromChild(e.getTarget());
23564 var index = this.indexOf(item);
23565 if(this.onItemClick(item, index, e) !== false){
23566 this.fireEvent("click", this, index, item, e);
23569 this.clearSelections();
23574 onContextMenu : function(e){
23575 var item = this.findItemFromChild(e.getTarget());
23577 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23582 onDblClick : function(e){
23583 var item = this.findItemFromChild(e.getTarget());
23585 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23589 onItemClick : function(item, index, e){
23590 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23593 if(this.multiSelect || this.singleSelect){
23594 if(this.multiSelect && e.shiftKey && this.lastSelection){
23595 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23597 this.select(item, this.multiSelect && e.ctrlKey);
23598 this.lastSelection = item;
23600 e.preventDefault();
23606 * Get the number of selected nodes.
23609 getSelectionCount : function(){
23610 return this.selections.length;
23614 * Get the currently selected nodes.
23615 * @return {Array} An array of HTMLElements
23617 getSelectedNodes : function(){
23618 return this.selections;
23622 * Get the indexes of the selected nodes.
23625 getSelectedIndexes : function(){
23626 var indexes = [], s = this.selections;
23627 for(var i = 0, len = s.length; i < len; i++){
23628 indexes.push(s[i].nodeIndex);
23634 * Clear all selections
23635 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23637 clearSelections : function(suppressEvent){
23638 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23639 this.cmp.elements = this.selections;
23640 this.cmp.removeClass(this.selectedClass);
23641 this.selections = [];
23642 if(!suppressEvent){
23643 this.fireEvent("selectionchange", this, this.selections);
23649 * Returns true if the passed node is selected
23650 * @param {HTMLElement/Number} node The node or node index
23651 * @return {Boolean}
23653 isSelected : function(node){
23654 var s = this.selections;
23658 node = this.getNode(node);
23659 return s.indexOf(node) !== -1;
23664 * @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
23665 * @param {Boolean} keepExisting (optional) true to keep existing selections
23666 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23668 select : function(nodeInfo, keepExisting, suppressEvent){
23669 if(nodeInfo instanceof Array){
23671 this.clearSelections(true);
23673 for(var i = 0, len = nodeInfo.length; i < len; i++){
23674 this.select(nodeInfo[i], true, true);
23677 var node = this.getNode(nodeInfo);
23678 if(node && !this.isSelected(node)){
23680 this.clearSelections(true);
23682 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23683 Roo.fly(node).addClass(this.selectedClass);
23684 this.selections.push(node);
23685 if(!suppressEvent){
23686 this.fireEvent("selectionchange", this, this.selections);
23694 * Gets a template node.
23695 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23696 * @return {HTMLElement} The node or null if it wasn't found
23698 getNode : function(nodeInfo){
23699 if(typeof nodeInfo == "string"){
23700 return document.getElementById(nodeInfo);
23701 }else if(typeof nodeInfo == "number"){
23702 return this.nodes[nodeInfo];
23708 * Gets a range template nodes.
23709 * @param {Number} startIndex
23710 * @param {Number} endIndex
23711 * @return {Array} An array of nodes
23713 getNodes : function(start, end){
23714 var ns = this.nodes;
23715 start = start || 0;
23716 end = typeof end == "undefined" ? ns.length - 1 : end;
23719 for(var i = start; i <= end; i++){
23723 for(var i = start; i >= end; i--){
23731 * Finds the index of the passed node
23732 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23733 * @return {Number} The index of the node or -1
23735 indexOf : function(node){
23736 node = this.getNode(node);
23737 if(typeof node.nodeIndex == "number"){
23738 return node.nodeIndex;
23740 var ns = this.nodes;
23741 for(var i = 0, len = ns.length; i < len; i++){
23751 * Ext JS Library 1.1.1
23752 * Copyright(c) 2006-2007, Ext JS, LLC.
23754 * Originally Released Under LGPL - original licence link has changed is not relivant.
23757 * <script type="text/javascript">
23761 * @class Roo.JsonView
23762 * @extends Roo.View
23763 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23765 var view = new Roo.JsonView({
23766 container: "my-element",
23767 template: '<div id="{id}">{foo} - {bar}</div>', // auto create template
23772 // listen for node click?
23773 view.on("click", function(vw, index, node, e){
23774 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23777 // direct load of JSON data
23778 view.load("foobar.php");
23780 // Example from my blog list
23781 var tpl = new Roo.Template(
23782 '<div class="entry">' +
23783 '<a class="entry-title" href="{link}">{title}</a>' +
23784 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23785 "</div><hr />"
23788 var moreView = new Roo.JsonView({
23789 container : "entry-list",
23793 moreView.on("beforerender", this.sortEntries, this);
23795 url: "/blog/get-posts.php",
23796 params: "allposts=true",
23797 text: "Loading Blog Entries..."
23801 * Note: old code is supported with arguments : (container, template, config)
23805 * Create a new JsonView
23807 * @param {Object} config The config object
23810 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
23813 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
23815 var um = this.el.getUpdateManager();
23816 um.setRenderer(this);
23817 um.on("update", this.onLoad, this);
23818 um.on("failure", this.onLoadException, this);
23821 * @event beforerender
23822 * Fires before rendering of the downloaded JSON data.
23823 * @param {Roo.JsonView} this
23824 * @param {Object} data The JSON data loaded
23828 * Fires when data is loaded.
23829 * @param {Roo.JsonView} this
23830 * @param {Object} data The JSON data loaded
23831 * @param {Object} response The raw Connect response object
23834 * @event loadexception
23835 * Fires when loading fails.
23836 * @param {Roo.JsonView} this
23837 * @param {Object} response The raw Connect response object
23840 'beforerender' : true,
23842 'loadexception' : true
23845 Roo.extend(Roo.JsonView, Roo.View, {
23847 * @type {String} The root property in the loaded JSON object that contains the data
23852 * Refreshes the view.
23854 refresh : function(){
23855 this.clearSelections();
23856 this.el.update("");
23858 var o = this.jsonData;
23859 if(o && o.length > 0){
23860 for(var i = 0, len = o.length; i < len; i++){
23861 var data = this.prepareData(o[i], i, o);
23862 html[html.length] = this.tpl.apply(data);
23865 html.push(this.emptyText);
23867 this.el.update(html.join(""));
23868 this.nodes = this.el.dom.childNodes;
23869 this.updateIndexes(0);
23873 * 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.
23874 * @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:
23877 url: "your-url.php",
23878 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
23879 callback: yourFunction,
23880 scope: yourObject, //(optional scope)
23883 text: "Loading...",
23888 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
23889 * 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.
23890 * @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}
23891 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
23892 * @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.
23895 var um = this.el.getUpdateManager();
23896 um.update.apply(um, arguments);
23899 render : function(el, response){
23900 this.clearSelections();
23901 this.el.update("");
23904 o = Roo.util.JSON.decode(response.responseText);
23907 o = /** eval:var:o */ eval("o." + this.jsonRoot);
23912 * The current JSON data or null
23915 this.beforeRender();
23920 * Get the number of records in the current JSON dataset
23923 getCount : function(){
23924 return this.jsonData ? this.jsonData.length : 0;
23928 * Returns the JSON object for the specified node(s)
23929 * @param {HTMLElement/Array} node The node or an array of nodes
23930 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
23931 * you get the JSON object for the node
23933 getNodeData : function(node){
23934 if(node instanceof Array){
23936 for(var i = 0, len = node.length; i < len; i++){
23937 data.push(this.getNodeData(node[i]));
23941 return this.jsonData[this.indexOf(node)] || null;
23944 beforeRender : function(){
23945 this.snapshot = this.jsonData;
23947 this.sort.apply(this, this.sortInfo);
23949 this.fireEvent("beforerender", this, this.jsonData);
23952 onLoad : function(el, o){
23953 this.fireEvent("load", this, this.jsonData, o);
23956 onLoadException : function(el, o){
23957 this.fireEvent("loadexception", this, o);
23961 * Filter the data by a specific property.
23962 * @param {String} property A property on your JSON objects
23963 * @param {String/RegExp} value Either string that the property values
23964 * should start with, or a RegExp to test against the property
23966 filter : function(property, value){
23969 var ss = this.snapshot;
23970 if(typeof value == "string"){
23971 var vlen = value.length;
23973 this.clearFilter();
23976 value = value.toLowerCase();
23977 for(var i = 0, len = ss.length; i < len; i++){
23979 if(o[property].substr(0, vlen).toLowerCase() == value){
23983 } else if(value.exec){ // regex?
23984 for(var i = 0, len = ss.length; i < len; i++){
23986 if(value.test(o[property])){
23993 this.jsonData = data;
23999 * Filter by a function. The passed function will be called with each
24000 * object in the current dataset. If the function returns true the value is kept,
24001 * otherwise it is filtered.
24002 * @param {Function} fn
24003 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24005 filterBy : function(fn, scope){
24008 var ss = this.snapshot;
24009 for(var i = 0, len = ss.length; i < len; i++){
24011 if(fn.call(scope || this, o)){
24015 this.jsonData = data;
24021 * Clears the current filter.
24023 clearFilter : function(){
24024 if(this.snapshot && this.jsonData != this.snapshot){
24025 this.jsonData = this.snapshot;
24032 * Sorts the data for this view and refreshes it.
24033 * @param {String} property A property on your JSON objects to sort on
24034 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24035 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24037 sort : function(property, dir, sortType){
24038 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24041 var dsc = dir && dir.toLowerCase() == "desc";
24042 var f = function(o1, o2){
24043 var v1 = sortType ? sortType(o1[p]) : o1[p];
24044 var v2 = sortType ? sortType(o2[p]) : o2[p];
24047 return dsc ? +1 : -1;
24048 } else if(v1 > v2){
24049 return dsc ? -1 : +1;
24054 this.jsonData.sort(f);
24056 if(this.jsonData != this.snapshot){
24057 this.snapshot.sort(f);
24063 * Ext JS Library 1.1.1
24064 * Copyright(c) 2006-2007, Ext JS, LLC.
24066 * Originally Released Under LGPL - original licence link has changed is not relivant.
24069 * <script type="text/javascript">
24074 * @class Roo.ColorPalette
24075 * @extends Roo.Component
24076 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24077 * Here's an example of typical usage:
24079 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24080 cp.render('my-div');
24082 cp.on('select', function(palette, selColor){
24083 // do something with selColor
24087 * Create a new ColorPalette
24088 * @param {Object} config The config object
24090 Roo.ColorPalette = function(config){
24091 Roo.ColorPalette.superclass.constructor.call(this, config);
24095 * Fires when a color is selected
24096 * @param {ColorPalette} this
24097 * @param {String} color The 6-digit color hex code (without the # symbol)
24103 this.on("select", this.handler, this.scope, true);
24106 Roo.extend(Roo.ColorPalette, Roo.Component, {
24108 * @cfg {String} itemCls
24109 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24111 itemCls : "x-color-palette",
24113 * @cfg {String} value
24114 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24115 * the hex codes are case-sensitive.
24118 clickEvent:'click',
24120 ctype: "Roo.ColorPalette",
24123 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24125 allowReselect : false,
24128 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24129 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24130 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24131 * of colors with the width setting until the box is symmetrical.</p>
24132 * <p>You can override individual colors if needed:</p>
24134 var cp = new Roo.ColorPalette();
24135 cp.colors[0] = "FF0000"; // change the first box to red
24138 Or you can provide a custom array of your own for complete control:
24140 var cp = new Roo.ColorPalette();
24141 cp.colors = ["000000", "993300", "333300"];
24146 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24147 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24148 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24149 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24150 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24154 onRender : function(container, position){
24155 var t = new Roo.MasterTemplate(
24156 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24158 var c = this.colors;
24159 for(var i = 0, len = c.length; i < len; i++){
24162 var el = document.createElement("div");
24163 el.className = this.itemCls;
24165 container.dom.insertBefore(el, position);
24166 this.el = Roo.get(el);
24167 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24168 if(this.clickEvent != 'click'){
24169 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24174 afterRender : function(){
24175 Roo.ColorPalette.superclass.afterRender.call(this);
24177 var s = this.value;
24184 handleClick : function(e, t){
24185 e.preventDefault();
24186 if(!this.disabled){
24187 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24188 this.select(c.toUpperCase());
24193 * Selects the specified color in the palette (fires the select event)
24194 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24196 select : function(color){
24197 color = color.replace("#", "");
24198 if(color != this.value || this.allowReselect){
24201 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24203 el.child("a.color-"+color).addClass("x-color-palette-sel");
24204 this.value = color;
24205 this.fireEvent("select", this, color);
24210 * Ext JS Library 1.1.1
24211 * Copyright(c) 2006-2007, Ext JS, LLC.
24213 * Originally Released Under LGPL - original licence link has changed is not relivant.
24216 * <script type="text/javascript">
24220 * @class Roo.DatePicker
24221 * @extends Roo.Component
24222 * Simple date picker class.
24224 * Create a new DatePicker
24225 * @param {Object} config The config object
24227 Roo.DatePicker = function(config){
24228 Roo.DatePicker.superclass.constructor.call(this, config);
24230 this.value = config && config.value ?
24231 config.value.clearTime() : new Date().clearTime();
24236 * Fires when a date is selected
24237 * @param {DatePicker} this
24238 * @param {Date} date The selected date
24244 this.on("select", this.handler, this.scope || this);
24246 // build the disabledDatesRE
24247 if(!this.disabledDatesRE && this.disabledDates){
24248 var dd = this.disabledDates;
24250 for(var i = 0; i < dd.length; i++){
24252 if(i != dd.length-1) re += "|";
24254 this.disabledDatesRE = new RegExp(re + ")");
24258 Roo.extend(Roo.DatePicker, Roo.Component, {
24260 * @cfg {String} todayText
24261 * The text to display on the button that selects the current date (defaults to "Today")
24263 todayText : "Today",
24265 * @cfg {String} okText
24266 * The text to display on the ok button
24268 okText : " OK ", //   to give the user extra clicking room
24270 * @cfg {String} cancelText
24271 * The text to display on the cancel button
24273 cancelText : "Cancel",
24275 * @cfg {String} todayTip
24276 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24278 todayTip : "{0} (Spacebar)",
24280 * @cfg {Date} minDate
24281 * Minimum allowable date (JavaScript date object, defaults to null)
24285 * @cfg {Date} maxDate
24286 * Maximum allowable date (JavaScript date object, defaults to null)
24290 * @cfg {String} minText
24291 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24293 minText : "This date is before the minimum date",
24295 * @cfg {String} maxText
24296 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24298 maxText : "This date is after the maximum date",
24300 * @cfg {String} format
24301 * The default date format string which can be overriden for localization support. The format must be
24302 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24306 * @cfg {Array} disabledDays
24307 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24309 disabledDays : null,
24311 * @cfg {String} disabledDaysText
24312 * The tooltip to display when the date falls on a disabled day (defaults to "")
24314 disabledDaysText : "",
24316 * @cfg {RegExp} disabledDatesRE
24317 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24319 disabledDatesRE : null,
24321 * @cfg {String} disabledDatesText
24322 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24324 disabledDatesText : "",
24326 * @cfg {Boolean} constrainToViewport
24327 * True to constrain the date picker to the viewport (defaults to true)
24329 constrainToViewport : true,
24331 * @cfg {Array} monthNames
24332 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24334 monthNames : Date.monthNames,
24336 * @cfg {Array} dayNames
24337 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24339 dayNames : Date.dayNames,
24341 * @cfg {String} nextText
24342 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24344 nextText: 'Next Month (Control+Right)',
24346 * @cfg {String} prevText
24347 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24349 prevText: 'Previous Month (Control+Left)',
24351 * @cfg {String} monthYearText
24352 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24354 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24356 * @cfg {Number} startDay
24357 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24361 * @cfg {Bool} showClear
24362 * Show a clear button (usefull for date form elements that can be blank.)
24368 * Sets the value of the date field
24369 * @param {Date} value The date to set
24371 setValue : function(value){
24372 var old = this.value;
24373 this.value = value.clearTime(true);
24375 this.update(this.value);
24380 * Gets the current selected value of the date field
24381 * @return {Date} The selected date
24383 getValue : function(){
24388 focus : function(){
24390 this.update(this.activeDate);
24395 onRender : function(container, position){
24397 '<table cellspacing="0">',
24398 '<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>',
24399 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24400 var dn = this.dayNames;
24401 for(var i = 0; i < 7; i++){
24402 var d = this.startDay+i;
24406 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24408 m[m.length] = "</tr></thead><tbody><tr>";
24409 for(var i = 0; i < 42; i++) {
24410 if(i % 7 == 0 && i != 0){
24411 m[m.length] = "</tr><tr>";
24413 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24415 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24416 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24418 var el = document.createElement("div");
24419 el.className = "x-date-picker";
24420 el.innerHTML = m.join("");
24422 container.dom.insertBefore(el, position);
24424 this.el = Roo.get(el);
24425 this.eventEl = Roo.get(el.firstChild);
24427 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24428 handler: this.showPrevMonth,
24430 preventDefault:true,
24434 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24435 handler: this.showNextMonth,
24437 preventDefault:true,
24441 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24443 this.monthPicker = this.el.down('div.x-date-mp');
24444 this.monthPicker.enableDisplayMode('block');
24446 var kn = new Roo.KeyNav(this.eventEl, {
24447 "left" : function(e){
24449 this.showPrevMonth() :
24450 this.update(this.activeDate.add("d", -1));
24453 "right" : function(e){
24455 this.showNextMonth() :
24456 this.update(this.activeDate.add("d", 1));
24459 "up" : function(e){
24461 this.showNextYear() :
24462 this.update(this.activeDate.add("d", -7));
24465 "down" : function(e){
24467 this.showPrevYear() :
24468 this.update(this.activeDate.add("d", 7));
24471 "pageUp" : function(e){
24472 this.showNextMonth();
24475 "pageDown" : function(e){
24476 this.showPrevMonth();
24479 "enter" : function(e){
24480 e.stopPropagation();
24487 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24489 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24491 this.el.unselectable();
24493 this.cells = this.el.select("table.x-date-inner tbody td");
24494 this.textNodes = this.el.query("table.x-date-inner tbody span");
24496 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24498 tooltip: this.monthYearText
24501 this.mbtn.on('click', this.showMonthPicker, this);
24502 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24505 var today = (new Date()).dateFormat(this.format);
24507 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24509 text: String.format(this.todayText, today),
24510 tooltip: String.format(this.todayTip, today),
24511 handler: this.selectToday,
24515 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24518 if (this.showClear) {
24520 baseTb.add( new Roo.Toolbar.Fill());
24523 cls: 'x-btn-icon x-btn-clear',
24524 handler: function() {
24526 this.fireEvent("select", this, '');
24536 this.update(this.value);
24539 createMonthPicker : function(){
24540 if(!this.monthPicker.dom.firstChild){
24541 var buf = ['<table border="0" cellspacing="0">'];
24542 for(var i = 0; i < 6; i++){
24544 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24545 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24547 '<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>' :
24548 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24552 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24554 '</button><button type="button" class="x-date-mp-cancel">',
24556 '</button></td></tr>',
24559 this.monthPicker.update(buf.join(''));
24560 this.monthPicker.on('click', this.onMonthClick, this);
24561 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24563 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24564 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24566 this.mpMonths.each(function(m, a, i){
24569 m.dom.xmonth = 5 + Math.round(i * .5);
24571 m.dom.xmonth = Math.round((i-1) * .5);
24577 showMonthPicker : function(){
24578 this.createMonthPicker();
24579 var size = this.el.getSize();
24580 this.monthPicker.setSize(size);
24581 this.monthPicker.child('table').setSize(size);
24583 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24584 this.updateMPMonth(this.mpSelMonth);
24585 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24586 this.updateMPYear(this.mpSelYear);
24588 this.monthPicker.slideIn('t', {duration:.2});
24591 updateMPYear : function(y){
24593 var ys = this.mpYears.elements;
24594 for(var i = 1; i <= 10; i++){
24595 var td = ys[i-1], y2;
24597 y2 = y + Math.round(i * .5);
24598 td.firstChild.innerHTML = y2;
24601 y2 = y - (5-Math.round(i * .5));
24602 td.firstChild.innerHTML = y2;
24605 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24609 updateMPMonth : function(sm){
24610 this.mpMonths.each(function(m, a, i){
24611 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24615 selectMPMonth: function(m){
24619 onMonthClick : function(e, t){
24621 var el = new Roo.Element(t), pn;
24622 if(el.is('button.x-date-mp-cancel')){
24623 this.hideMonthPicker();
24625 else if(el.is('button.x-date-mp-ok')){
24626 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24627 this.hideMonthPicker();
24629 else if(pn = el.up('td.x-date-mp-month', 2)){
24630 this.mpMonths.removeClass('x-date-mp-sel');
24631 pn.addClass('x-date-mp-sel');
24632 this.mpSelMonth = pn.dom.xmonth;
24634 else if(pn = el.up('td.x-date-mp-year', 2)){
24635 this.mpYears.removeClass('x-date-mp-sel');
24636 pn.addClass('x-date-mp-sel');
24637 this.mpSelYear = pn.dom.xyear;
24639 else if(el.is('a.x-date-mp-prev')){
24640 this.updateMPYear(this.mpyear-10);
24642 else if(el.is('a.x-date-mp-next')){
24643 this.updateMPYear(this.mpyear+10);
24647 onMonthDblClick : function(e, t){
24649 var el = new Roo.Element(t), pn;
24650 if(pn = el.up('td.x-date-mp-month', 2)){
24651 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24652 this.hideMonthPicker();
24654 else if(pn = el.up('td.x-date-mp-year', 2)){
24655 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24656 this.hideMonthPicker();
24660 hideMonthPicker : function(disableAnim){
24661 if(this.monthPicker){
24662 if(disableAnim === true){
24663 this.monthPicker.hide();
24665 this.monthPicker.slideOut('t', {duration:.2});
24671 showPrevMonth : function(e){
24672 this.update(this.activeDate.add("mo", -1));
24676 showNextMonth : function(e){
24677 this.update(this.activeDate.add("mo", 1));
24681 showPrevYear : function(){
24682 this.update(this.activeDate.add("y", -1));
24686 showNextYear : function(){
24687 this.update(this.activeDate.add("y", 1));
24691 handleMouseWheel : function(e){
24692 var delta = e.getWheelDelta();
24694 this.showPrevMonth();
24696 } else if(delta < 0){
24697 this.showNextMonth();
24703 handleDateClick : function(e, t){
24705 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24706 this.setValue(new Date(t.dateValue));
24707 this.fireEvent("select", this, this.value);
24712 selectToday : function(){
24713 this.setValue(new Date().clearTime());
24714 this.fireEvent("select", this, this.value);
24718 update : function(date){
24719 var vd = this.activeDate;
24720 this.activeDate = date;
24722 var t = date.getTime();
24723 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24724 this.cells.removeClass("x-date-selected");
24725 this.cells.each(function(c){
24726 if(c.dom.firstChild.dateValue == t){
24727 c.addClass("x-date-selected");
24728 setTimeout(function(){
24729 try{c.dom.firstChild.focus();}catch(e){}
24737 var days = date.getDaysInMonth();
24738 var firstOfMonth = date.getFirstDateOfMonth();
24739 var startingPos = firstOfMonth.getDay()-this.startDay;
24741 if(startingPos <= this.startDay){
24745 var pm = date.add("mo", -1);
24746 var prevStart = pm.getDaysInMonth()-startingPos;
24748 var cells = this.cells.elements;
24749 var textEls = this.textNodes;
24750 days += startingPos;
24752 // convert everything to numbers so it's fast
24753 var day = 86400000;
24754 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24755 var today = new Date().clearTime().getTime();
24756 var sel = date.clearTime().getTime();
24757 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24758 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24759 var ddMatch = this.disabledDatesRE;
24760 var ddText = this.disabledDatesText;
24761 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24762 var ddaysText = this.disabledDaysText;
24763 var format = this.format;
24765 var setCellClass = function(cal, cell){
24767 var t = d.getTime();
24768 cell.firstChild.dateValue = t;
24770 cell.className += " x-date-today";
24771 cell.title = cal.todayText;
24774 cell.className += " x-date-selected";
24775 setTimeout(function(){
24776 try{cell.firstChild.focus();}catch(e){}
24781 cell.className = " x-date-disabled";
24782 cell.title = cal.minText;
24786 cell.className = " x-date-disabled";
24787 cell.title = cal.maxText;
24791 if(ddays.indexOf(d.getDay()) != -1){
24792 cell.title = ddaysText;
24793 cell.className = " x-date-disabled";
24796 if(ddMatch && format){
24797 var fvalue = d.dateFormat(format);
24798 if(ddMatch.test(fvalue)){
24799 cell.title = ddText.replace("%0", fvalue);
24800 cell.className = " x-date-disabled";
24806 for(; i < startingPos; i++) {
24807 textEls[i].innerHTML = (++prevStart);
24808 d.setDate(d.getDate()+1);
24809 cells[i].className = "x-date-prevday";
24810 setCellClass(this, cells[i]);
24812 for(; i < days; i++){
24813 intDay = i - startingPos + 1;
24814 textEls[i].innerHTML = (intDay);
24815 d.setDate(d.getDate()+1);
24816 cells[i].className = "x-date-active";
24817 setCellClass(this, cells[i]);
24820 for(; i < 42; i++) {
24821 textEls[i].innerHTML = (++extraDays);
24822 d.setDate(d.getDate()+1);
24823 cells[i].className = "x-date-nextday";
24824 setCellClass(this, cells[i]);
24827 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
24829 if(!this.internalRender){
24830 var main = this.el.dom.firstChild;
24831 var w = main.offsetWidth;
24832 this.el.setWidth(w + this.el.getBorderWidth("lr"));
24833 Roo.fly(main).setWidth(w);
24834 this.internalRender = true;
24835 // opera does not respect the auto grow header center column
24836 // then, after it gets a width opera refuses to recalculate
24837 // without a second pass
24838 if(Roo.isOpera && !this.secondPass){
24839 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
24840 this.secondPass = true;
24841 this.update.defer(10, this, [date]);
24847 * Ext JS Library 1.1.1
24848 * Copyright(c) 2006-2007, Ext JS, LLC.
24850 * Originally Released Under LGPL - original licence link has changed is not relivant.
24853 * <script type="text/javascript">
24856 * @class Roo.TabPanel
24857 * @extends Roo.util.Observable
24858 * A lightweight tab container.
24862 // basic tabs 1, built from existing content
24863 var tabs = new Roo.TabPanel("tabs1");
24864 tabs.addTab("script", "View Script");
24865 tabs.addTab("markup", "View Markup");
24866 tabs.activate("script");
24868 // more advanced tabs, built from javascript
24869 var jtabs = new Roo.TabPanel("jtabs");
24870 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
24872 // set up the UpdateManager
24873 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
24874 var updater = tab2.getUpdateManager();
24875 updater.setDefaultUrl("ajax1.htm");
24876 tab2.on('activate', updater.refresh, updater, true);
24878 // Use setUrl for Ajax loading
24879 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
24880 tab3.setUrl("ajax2.htm", null, true);
24883 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
24886 jtabs.activate("jtabs-1");
24889 * Create a new TabPanel.
24890 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
24891 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
24893 Roo.TabPanel = function(container, config){
24895 * The container element for this TabPanel.
24896 * @type Roo.Element
24898 this.el = Roo.get(container, true);
24900 if(typeof config == "boolean"){
24901 this.tabPosition = config ? "bottom" : "top";
24903 Roo.apply(this, config);
24906 if(this.tabPosition == "bottom"){
24907 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24908 this.el.addClass("x-tabs-bottom");
24910 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
24911 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
24912 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
24914 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
24916 if(this.tabPosition != "bottom"){
24917 /** The body element that contains {@link Roo.TabPanelItem} bodies.
24918 * @type Roo.Element
24920 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24921 this.el.addClass("x-tabs-top");
24925 this.bodyEl.setStyle("position", "relative");
24927 this.active = null;
24928 this.activateDelegate = this.activate.createDelegate(this);
24933 * Fires when the active tab changes
24934 * @param {Roo.TabPanel} this
24935 * @param {Roo.TabPanelItem} activePanel The new active tab
24939 * @event beforetabchange
24940 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
24941 * @param {Roo.TabPanel} this
24942 * @param {Object} e Set cancel to true on this object to cancel the tab change
24943 * @param {Roo.TabPanelItem} tab The tab being changed to
24945 "beforetabchange" : true
24948 Roo.EventManager.onWindowResize(this.onResize, this);
24949 this.cpad = this.el.getPadding("lr");
24950 this.hiddenCount = 0;
24952 Roo.TabPanel.superclass.constructor.call(this);
24955 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
24957 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
24959 tabPosition : "top",
24961 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
24963 currentTabWidth : 0,
24965 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
24969 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
24973 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
24975 preferredTabWidth : 175,
24977 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
24979 resizeTabs : false,
24981 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
24983 monitorResize : true,
24986 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
24987 * @param {String} id The id of the div to use <b>or create</b>
24988 * @param {String} text The text for the tab
24989 * @param {String} content (optional) Content to put in the TabPanelItem body
24990 * @param {Boolean} closable (optional) True to create a close icon on the tab
24991 * @return {Roo.TabPanelItem} The created TabPanelItem
24993 addTab : function(id, text, content, closable){
24994 var item = new Roo.TabPanelItem(this, id, text, closable);
24995 this.addTabItem(item);
24997 item.setContent(content);
25003 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25004 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25005 * @return {Roo.TabPanelItem}
25007 getTab : function(id){
25008 return this.items[id];
25012 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25013 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25015 hideTab : function(id){
25016 var t = this.items[id];
25019 this.hiddenCount++;
25020 this.autoSizeTabs();
25025 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25026 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25028 unhideTab : function(id){
25029 var t = this.items[id];
25031 t.setHidden(false);
25032 this.hiddenCount--;
25033 this.autoSizeTabs();
25038 * Adds an existing {@link Roo.TabPanelItem}.
25039 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25041 addTabItem : function(item){
25042 this.items[item.id] = item;
25043 this.items.push(item);
25044 if(this.resizeTabs){
25045 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25046 this.autoSizeTabs();
25053 * Removes a {@link Roo.TabPanelItem}.
25054 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25056 removeTab : function(id){
25057 var items = this.items;
25058 var tab = items[id];
25060 var index = items.indexOf(tab);
25061 if(this.active == tab && items.length > 1){
25062 var newTab = this.getNextAvailable(index);
25063 if(newTab)newTab.activate();
25065 this.stripEl.dom.removeChild(tab.pnode.dom);
25066 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25067 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25069 items.splice(index, 1);
25070 delete this.items[tab.id];
25071 tab.fireEvent("close", tab);
25072 tab.purgeListeners();
25073 this.autoSizeTabs();
25076 getNextAvailable : function(start){
25077 var items = this.items;
25079 // look for a next tab that will slide over to
25080 // replace the one being removed
25081 while(index < items.length){
25082 var item = items[++index];
25083 if(item && !item.isHidden()){
25087 // if one isn't found select the previous tab (on the left)
25090 var item = items[--index];
25091 if(item && !item.isHidden()){
25099 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25100 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25102 disableTab : function(id){
25103 var tab = this.items[id];
25104 if(tab && this.active != tab){
25110 * Enables a {@link Roo.TabPanelItem} that is disabled.
25111 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25113 enableTab : function(id){
25114 var tab = this.items[id];
25119 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25120 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25121 * @return {Roo.TabPanelItem} The TabPanelItem.
25123 activate : function(id){
25124 var tab = this.items[id];
25128 if(tab == this.active || tab.disabled){
25132 this.fireEvent("beforetabchange", this, e, tab);
25133 if(e.cancel !== true && !tab.disabled){
25135 this.active.hide();
25137 this.active = this.items[id];
25138 this.active.show();
25139 this.fireEvent("tabchange", this, this.active);
25145 * Gets the active {@link Roo.TabPanelItem}.
25146 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25148 getActiveTab : function(){
25149 return this.active;
25153 * Updates the tab body element to fit the height of the container element
25154 * for overflow scrolling
25155 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25157 syncHeight : function(targetHeight){
25158 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25159 var bm = this.bodyEl.getMargins();
25160 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25161 this.bodyEl.setHeight(newHeight);
25165 onResize : function(){
25166 if(this.monitorResize){
25167 this.autoSizeTabs();
25172 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25174 beginUpdate : function(){
25175 this.updating = true;
25179 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25181 endUpdate : function(){
25182 this.updating = false;
25183 this.autoSizeTabs();
25187 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25189 autoSizeTabs : function(){
25190 var count = this.items.length;
25191 var vcount = count - this.hiddenCount;
25192 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25193 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25194 var availWidth = Math.floor(w / vcount);
25195 var b = this.stripBody;
25196 if(b.getWidth() > w){
25197 var tabs = this.items;
25198 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25199 if(availWidth < this.minTabWidth){
25200 /*if(!this.sleft){ // incomplete scrolling code
25201 this.createScrollButtons();
25204 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25207 if(this.currentTabWidth < this.preferredTabWidth){
25208 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25214 * Returns the number of tabs in this TabPanel.
25217 getCount : function(){
25218 return this.items.length;
25222 * Resizes all the tabs to the passed width
25223 * @param {Number} The new width
25225 setTabWidth : function(width){
25226 this.currentTabWidth = width;
25227 for(var i = 0, len = this.items.length; i < len; i++) {
25228 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25233 * Destroys this TabPanel
25234 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25236 destroy : function(removeEl){
25237 Roo.EventManager.removeResizeListener(this.onResize, this);
25238 for(var i = 0, len = this.items.length; i < len; i++){
25239 this.items[i].purgeListeners();
25241 if(removeEl === true){
25242 this.el.update("");
25249 * @class Roo.TabPanelItem
25250 * @extends Roo.util.Observable
25251 * Represents an individual item (tab plus body) in a TabPanel.
25252 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25253 * @param {String} id The id of this TabPanelItem
25254 * @param {String} text The text for the tab of this TabPanelItem
25255 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25257 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25259 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25260 * @type Roo.TabPanel
25262 this.tabPanel = tabPanel;
25264 * The id for this TabPanelItem
25269 this.disabled = false;
25273 this.loaded = false;
25274 this.closable = closable;
25277 * The body element for this TabPanelItem.
25278 * @type Roo.Element
25280 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25281 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25282 this.bodyEl.setStyle("display", "block");
25283 this.bodyEl.setStyle("zoom", "1");
25286 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25288 this.el = Roo.get(els.el, true);
25289 this.inner = Roo.get(els.inner, true);
25290 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25291 this.pnode = Roo.get(els.el.parentNode, true);
25292 this.el.on("mousedown", this.onTabMouseDown, this);
25293 this.el.on("click", this.onTabClick, this);
25296 var c = Roo.get(els.close, true);
25297 c.dom.title = this.closeText;
25298 c.addClassOnOver("close-over");
25299 c.on("click", this.closeClick, this);
25305 * Fires when this tab becomes the active tab.
25306 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25307 * @param {Roo.TabPanelItem} this
25311 * @event beforeclose
25312 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25313 * @param {Roo.TabPanelItem} this
25314 * @param {Object} e Set cancel to true on this object to cancel the close.
25316 "beforeclose": true,
25319 * Fires when this tab is closed.
25320 * @param {Roo.TabPanelItem} this
25324 * @event deactivate
25325 * Fires when this tab is no longer the active tab.
25326 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25327 * @param {Roo.TabPanelItem} this
25329 "deactivate" : true
25331 this.hidden = false;
25333 Roo.TabPanelItem.superclass.constructor.call(this);
25336 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25337 purgeListeners : function(){
25338 Roo.util.Observable.prototype.purgeListeners.call(this);
25339 this.el.removeAllListeners();
25342 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25345 this.pnode.addClass("on");
25348 this.tabPanel.stripWrap.repaint();
25350 this.fireEvent("activate", this.tabPanel, this);
25354 * Returns true if this tab is the active tab.
25355 * @return {Boolean}
25357 isActive : function(){
25358 return this.tabPanel.getActiveTab() == this;
25362 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25365 this.pnode.removeClass("on");
25367 this.fireEvent("deactivate", this.tabPanel, this);
25370 hideAction : function(){
25371 this.bodyEl.hide();
25372 this.bodyEl.setStyle("position", "absolute");
25373 this.bodyEl.setLeft("-20000px");
25374 this.bodyEl.setTop("-20000px");
25377 showAction : function(){
25378 this.bodyEl.setStyle("position", "relative");
25379 this.bodyEl.setTop("");
25380 this.bodyEl.setLeft("");
25381 this.bodyEl.show();
25385 * Set the tooltip for the tab.
25386 * @param {String} tooltip The tab's tooltip
25388 setTooltip : function(text){
25389 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25390 this.textEl.dom.qtip = text;
25391 this.textEl.dom.removeAttribute('title');
25393 this.textEl.dom.title = text;
25397 onTabClick : function(e){
25398 e.preventDefault();
25399 this.tabPanel.activate(this.id);
25402 onTabMouseDown : function(e){
25403 e.preventDefault();
25404 this.tabPanel.activate(this.id);
25407 getWidth : function(){
25408 return this.inner.getWidth();
25411 setWidth : function(width){
25412 var iwidth = width - this.pnode.getPadding("lr");
25413 this.inner.setWidth(iwidth);
25414 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25415 this.pnode.setWidth(width);
25419 * Show or hide the tab
25420 * @param {Boolean} hidden True to hide or false to show.
25422 setHidden : function(hidden){
25423 this.hidden = hidden;
25424 this.pnode.setStyle("display", hidden ? "none" : "");
25428 * Returns true if this tab is "hidden"
25429 * @return {Boolean}
25431 isHidden : function(){
25432 return this.hidden;
25436 * Returns the text for this tab
25439 getText : function(){
25443 autoSize : function(){
25444 //this.el.beginMeasure();
25445 this.textEl.setWidth(1);
25446 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25447 //this.el.endMeasure();
25451 * Sets the text for the tab (Note: this also sets the tooltip text)
25452 * @param {String} text The tab's text and tooltip
25454 setText : function(text){
25456 this.textEl.update(text);
25457 this.setTooltip(text);
25458 if(!this.tabPanel.resizeTabs){
25463 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25465 activate : function(){
25466 this.tabPanel.activate(this.id);
25470 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25472 disable : function(){
25473 if(this.tabPanel.active != this){
25474 this.disabled = true;
25475 this.pnode.addClass("disabled");
25480 * Enables this TabPanelItem if it was previously disabled.
25482 enable : function(){
25483 this.disabled = false;
25484 this.pnode.removeClass("disabled");
25488 * Sets the content for this TabPanelItem.
25489 * @param {String} content The content
25490 * @param {Boolean} loadScripts true to look for and load scripts
25492 setContent : function(content, loadScripts){
25493 this.bodyEl.update(content, loadScripts);
25497 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25498 * @return {Roo.UpdateManager} The UpdateManager
25500 getUpdateManager : function(){
25501 return this.bodyEl.getUpdateManager();
25505 * Set a URL to be used to load the content for this TabPanelItem.
25506 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25507 * @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)
25508 * @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)
25509 * @return {Roo.UpdateManager} The UpdateManager
25511 setUrl : function(url, params, loadOnce){
25512 if(this.refreshDelegate){
25513 this.un('activate', this.refreshDelegate);
25515 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25516 this.on("activate", this.refreshDelegate);
25517 return this.bodyEl.getUpdateManager();
25521 _handleRefresh : function(url, params, loadOnce){
25522 if(!loadOnce || !this.loaded){
25523 var updater = this.bodyEl.getUpdateManager();
25524 updater.update(url, params, this._setLoaded.createDelegate(this));
25529 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25530 * Will fail silently if the setUrl method has not been called.
25531 * This does not activate the panel, just updates its content.
25533 refresh : function(){
25534 if(this.refreshDelegate){
25535 this.loaded = false;
25536 this.refreshDelegate();
25541 _setLoaded : function(){
25542 this.loaded = true;
25546 closeClick : function(e){
25549 this.fireEvent("beforeclose", this, o);
25550 if(o.cancel !== true){
25551 this.tabPanel.removeTab(this.id);
25555 * The text displayed in the tooltip for the close icon.
25558 closeText : "Close this tab"
25562 Roo.TabPanel.prototype.createStrip = function(container){
25563 var strip = document.createElement("div");
25564 strip.className = "x-tabs-wrap";
25565 container.appendChild(strip);
25569 Roo.TabPanel.prototype.createStripList = function(strip){
25570 // div wrapper for retard IE
25571 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>';
25572 return strip.firstChild.firstChild.firstChild.firstChild;
25575 Roo.TabPanel.prototype.createBody = function(container){
25576 var body = document.createElement("div");
25577 Roo.id(body, "tab-body");
25578 Roo.fly(body).addClass("x-tabs-body");
25579 container.appendChild(body);
25583 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25584 var body = Roo.getDom(id);
25586 body = document.createElement("div");
25589 Roo.fly(body).addClass("x-tabs-item-body");
25590 bodyEl.insertBefore(body, bodyEl.firstChild);
25594 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25595 var td = document.createElement("td");
25596 stripEl.appendChild(td);
25598 td.className = "x-tabs-closable";
25599 if(!this.closeTpl){
25600 this.closeTpl = new Roo.Template(
25601 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25602 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25603 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25606 var el = this.closeTpl.overwrite(td, {"text": text});
25607 var close = el.getElementsByTagName("div")[0];
25608 var inner = el.getElementsByTagName("em")[0];
25609 return {"el": el, "close": close, "inner": inner};
25612 this.tabTpl = new Roo.Template(
25613 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25614 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25617 var el = this.tabTpl.overwrite(td, {"text": text});
25618 var inner = el.getElementsByTagName("em")[0];
25619 return {"el": el, "inner": inner};
25623 * Ext JS Library 1.1.1
25624 * Copyright(c) 2006-2007, Ext JS, LLC.
25626 * Originally Released Under LGPL - original licence link has changed is not relivant.
25629 * <script type="text/javascript">
25633 * @class Roo.Button
25634 * @extends Roo.util.Observable
25635 * Simple Button class
25636 * @cfg {String} text The button text
25637 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25638 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25639 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25640 * @cfg {Object} scope The scope of the handler
25641 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25642 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25643 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25644 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25645 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25646 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25647 applies if enableToggle = true)
25648 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25649 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25650 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25652 * Create a new button
25653 * @param {Object} config The config object
25655 Roo.Button = function(renderTo, config)
25659 renderTo = config.renderTo || false;
25662 Roo.apply(this, config);
25666 * Fires when this button is clicked
25667 * @param {Button} this
25668 * @param {EventObject} e The click event
25673 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25674 * @param {Button} this
25675 * @param {Boolean} pressed
25680 * Fires when the mouse hovers over the button
25681 * @param {Button} this
25682 * @param {Event} e The event object
25684 'mouseover' : true,
25687 * Fires when the mouse exits the button
25688 * @param {Button} this
25689 * @param {Event} e The event object
25694 * Fires when the button is rendered
25695 * @param {Button} this
25700 this.menu = Roo.menu.MenuMgr.get(this.menu);
25703 this.render(renderTo);
25706 Roo.util.Observable.call(this);
25709 Roo.extend(Roo.Button, Roo.util.Observable, {
25715 * Read-only. True if this button is hidden
25720 * Read-only. True if this button is disabled
25725 * Read-only. True if this button is pressed (only if enableToggle = true)
25731 * @cfg {Number} tabIndex
25732 * The DOM tabIndex for this button (defaults to undefined)
25734 tabIndex : undefined,
25737 * @cfg {Boolean} enableToggle
25738 * True to enable pressed/not pressed toggling (defaults to false)
25740 enableToggle: false,
25742 * @cfg {Mixed} menu
25743 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25747 * @cfg {String} menuAlign
25748 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25750 menuAlign : "tl-bl?",
25753 * @cfg {String} iconCls
25754 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25756 iconCls : undefined,
25758 * @cfg {String} type
25759 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25764 menuClassTarget: 'tr',
25767 * @cfg {String} clickEvent
25768 * The type of event to map to the button's event handler (defaults to 'click')
25770 clickEvent : 'click',
25773 * @cfg {Boolean} handleMouseEvents
25774 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25776 handleMouseEvents : true,
25779 * @cfg {String} tooltipType
25780 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25782 tooltipType : 'qtip',
25785 * @cfg {String} cls
25786 * A CSS class to apply to the button's main element.
25790 * @cfg {Roo.Template} template (Optional)
25791 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25792 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25793 * require code modifications if required elements (e.g. a button) aren't present.
25797 render : function(renderTo){
25799 if(this.hideParent){
25800 this.parentEl = Roo.get(renderTo);
25802 if(!this.dhconfig){
25803 if(!this.template){
25804 if(!Roo.Button.buttonTemplate){
25805 // hideous table template
25806 Roo.Button.buttonTemplate = new Roo.Template(
25807 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
25808 '<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>',
25809 "</tr></tbody></table>");
25811 this.template = Roo.Button.buttonTemplate;
25813 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
25814 var btnEl = btn.child("button:first");
25815 btnEl.on('focus', this.onFocus, this);
25816 btnEl.on('blur', this.onBlur, this);
25818 btn.addClass(this.cls);
25821 btnEl.setStyle('background-image', 'url(' +this.icon +')');
25824 btnEl.addClass(this.iconCls);
25826 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
25829 if(this.tabIndex !== undefined){
25830 btnEl.dom.tabIndex = this.tabIndex;
25833 if(typeof this.tooltip == 'object'){
25834 Roo.QuickTips.tips(Roo.apply({
25838 btnEl.dom[this.tooltipType] = this.tooltip;
25842 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
25846 this.el.dom.id = this.el.id = this.id;
25849 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
25850 this.menu.on("show", this.onMenuShow, this);
25851 this.menu.on("hide", this.onMenuHide, this);
25853 btn.addClass("x-btn");
25854 if(Roo.isIE && !Roo.isIE7){
25855 this.autoWidth.defer(1, this);
25859 if(this.handleMouseEvents){
25860 btn.on("mouseover", this.onMouseOver, this);
25861 btn.on("mouseout", this.onMouseOut, this);
25862 btn.on("mousedown", this.onMouseDown, this);
25864 btn.on(this.clickEvent, this.onClick, this);
25865 //btn.on("mouseup", this.onMouseUp, this);
25872 Roo.ButtonToggleMgr.register(this);
25874 this.el.addClass("x-btn-pressed");
25877 var repeater = new Roo.util.ClickRepeater(btn,
25878 typeof this.repeat == "object" ? this.repeat : {}
25880 repeater.on("click", this.onClick, this);
25882 this.fireEvent('render', this);
25886 * Returns the button's underlying element
25887 * @return {Roo.Element} The element
25889 getEl : function(){
25894 * Destroys this Button and removes any listeners.
25896 destroy : function(){
25897 Roo.ButtonToggleMgr.unregister(this);
25898 this.el.removeAllListeners();
25899 this.purgeListeners();
25904 autoWidth : function(){
25906 this.el.setWidth("auto");
25907 if(Roo.isIE7 && Roo.isStrict){
25908 var ib = this.el.child('button');
25909 if(ib && ib.getWidth() > 20){
25911 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
25916 this.el.beginMeasure();
25918 if(this.el.getWidth() < this.minWidth){
25919 this.el.setWidth(this.minWidth);
25922 this.el.endMeasure();
25929 * Assigns this button's click handler
25930 * @param {Function} handler The function to call when the button is clicked
25931 * @param {Object} scope (optional) Scope for the function passed in
25933 setHandler : function(handler, scope){
25934 this.handler = handler;
25935 this.scope = scope;
25939 * Sets this button's text
25940 * @param {String} text The button text
25942 setText : function(text){
25945 this.el.child("td.x-btn-center button.x-btn-text").update(text);
25951 * Gets the text for this button
25952 * @return {String} The button text
25954 getText : function(){
25962 this.hidden = false;
25964 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
25972 this.hidden = true;
25974 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
25979 * Convenience function for boolean show/hide
25980 * @param {Boolean} visible True to show, false to hide
25982 setVisible: function(visible){
25991 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
25992 * @param {Boolean} state (optional) Force a particular state
25994 toggle : function(state){
25995 state = state === undefined ? !this.pressed : state;
25996 if(state != this.pressed){
25998 this.el.addClass("x-btn-pressed");
25999 this.pressed = true;
26000 this.fireEvent("toggle", this, true);
26002 this.el.removeClass("x-btn-pressed");
26003 this.pressed = false;
26004 this.fireEvent("toggle", this, false);
26006 if(this.toggleHandler){
26007 this.toggleHandler.call(this.scope || this, this, state);
26015 focus : function(){
26016 this.el.child('button:first').focus();
26020 * Disable this button
26022 disable : function(){
26024 this.el.addClass("x-btn-disabled");
26026 this.disabled = true;
26030 * Enable this button
26032 enable : function(){
26034 this.el.removeClass("x-btn-disabled");
26036 this.disabled = false;
26040 * Convenience function for boolean enable/disable
26041 * @param {Boolean} enabled True to enable, false to disable
26043 setDisabled : function(v){
26044 this[v !== true ? "enable" : "disable"]();
26048 onClick : function(e){
26050 e.preventDefault();
26055 if(!this.disabled){
26056 if(this.enableToggle){
26059 if(this.menu && !this.menu.isVisible()){
26060 this.menu.show(this.el, this.menuAlign);
26062 this.fireEvent("click", this, e);
26064 this.el.removeClass("x-btn-over");
26065 this.handler.call(this.scope || this, this, e);
26070 onMouseOver : function(e){
26071 if(!this.disabled){
26072 this.el.addClass("x-btn-over");
26073 this.fireEvent('mouseover', this, e);
26077 onMouseOut : function(e){
26078 if(!e.within(this.el, true)){
26079 this.el.removeClass("x-btn-over");
26080 this.fireEvent('mouseout', this, e);
26084 onFocus : function(e){
26085 if(!this.disabled){
26086 this.el.addClass("x-btn-focus");
26090 onBlur : function(e){
26091 this.el.removeClass("x-btn-focus");
26094 onMouseDown : function(e){
26095 if(!this.disabled && e.button == 0){
26096 this.el.addClass("x-btn-click");
26097 Roo.get(document).on('mouseup', this.onMouseUp, this);
26101 onMouseUp : function(e){
26103 this.el.removeClass("x-btn-click");
26104 Roo.get(document).un('mouseup', this.onMouseUp, this);
26108 onMenuShow : function(e){
26109 this.el.addClass("x-btn-menu-active");
26112 onMenuHide : function(e){
26113 this.el.removeClass("x-btn-menu-active");
26117 // Private utility class used by Button
26118 Roo.ButtonToggleMgr = function(){
26121 function toggleGroup(btn, state){
26123 var g = groups[btn.toggleGroup];
26124 for(var i = 0, l = g.length; i < l; i++){
26126 g[i].toggle(false);
26133 register : function(btn){
26134 if(!btn.toggleGroup){
26137 var g = groups[btn.toggleGroup];
26139 g = groups[btn.toggleGroup] = [];
26142 btn.on("toggle", toggleGroup);
26145 unregister : function(btn){
26146 if(!btn.toggleGroup){
26149 var g = groups[btn.toggleGroup];
26152 btn.un("toggle", toggleGroup);
26158 * Ext JS Library 1.1.1
26159 * Copyright(c) 2006-2007, Ext JS, LLC.
26161 * Originally Released Under LGPL - original licence link has changed is not relivant.
26164 * <script type="text/javascript">
26168 * @class Roo.SplitButton
26169 * @extends Roo.Button
26170 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26171 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26172 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26173 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26174 * @cfg {String} arrowTooltip The title attribute of the arrow
26176 * Create a new menu button
26177 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26178 * @param {Object} config The config object
26180 Roo.SplitButton = function(renderTo, config){
26181 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26183 * @event arrowclick
26184 * Fires when this button's arrow is clicked
26185 * @param {SplitButton} this
26186 * @param {EventObject} e The click event
26188 this.addEvents({"arrowclick":true});
26191 Roo.extend(Roo.SplitButton, Roo.Button, {
26192 render : function(renderTo){
26193 // this is one sweet looking template!
26194 var tpl = new Roo.Template(
26195 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26196 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26197 '<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>',
26198 "</tbody></table></td><td>",
26199 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26200 '<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>',
26201 "</tbody></table></td></tr></table>"
26203 var btn = tpl.append(renderTo, [this.text, this.type], true);
26204 var btnEl = btn.child("button");
26206 btn.addClass(this.cls);
26209 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26212 btnEl.addClass(this.iconCls);
26214 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26218 if(this.handleMouseEvents){
26219 btn.on("mouseover", this.onMouseOver, this);
26220 btn.on("mouseout", this.onMouseOut, this);
26221 btn.on("mousedown", this.onMouseDown, this);
26222 btn.on("mouseup", this.onMouseUp, this);
26224 btn.on(this.clickEvent, this.onClick, this);
26226 if(typeof this.tooltip == 'object'){
26227 Roo.QuickTips.tips(Roo.apply({
26231 btnEl.dom[this.tooltipType] = this.tooltip;
26234 if(this.arrowTooltip){
26235 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26244 this.el.addClass("x-btn-pressed");
26246 if(Roo.isIE && !Roo.isIE7){
26247 this.autoWidth.defer(1, this);
26252 this.menu.on("show", this.onMenuShow, this);
26253 this.menu.on("hide", this.onMenuHide, this);
26255 this.fireEvent('render', this);
26259 autoWidth : function(){
26261 var tbl = this.el.child("table:first");
26262 var tbl2 = this.el.child("table:last");
26263 this.el.setWidth("auto");
26264 tbl.setWidth("auto");
26265 if(Roo.isIE7 && Roo.isStrict){
26266 var ib = this.el.child('button:first');
26267 if(ib && ib.getWidth() > 20){
26269 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26274 this.el.beginMeasure();
26276 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26277 tbl.setWidth(this.minWidth-tbl2.getWidth());
26280 this.el.endMeasure();
26283 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26287 * Sets this button's click handler
26288 * @param {Function} handler The function to call when the button is clicked
26289 * @param {Object} scope (optional) Scope for the function passed above
26291 setHandler : function(handler, scope){
26292 this.handler = handler;
26293 this.scope = scope;
26297 * Sets this button's arrow click handler
26298 * @param {Function} handler The function to call when the arrow is clicked
26299 * @param {Object} scope (optional) Scope for the function passed above
26301 setArrowHandler : function(handler, scope){
26302 this.arrowHandler = handler;
26303 this.scope = scope;
26309 focus : function(){
26311 this.el.child("button:first").focus();
26316 onClick : function(e){
26317 e.preventDefault();
26318 if(!this.disabled){
26319 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26320 if(this.menu && !this.menu.isVisible()){
26321 this.menu.show(this.el, this.menuAlign);
26323 this.fireEvent("arrowclick", this, e);
26324 if(this.arrowHandler){
26325 this.arrowHandler.call(this.scope || this, this, e);
26328 this.fireEvent("click", this, e);
26330 this.handler.call(this.scope || this, this, e);
26336 onMouseDown : function(e){
26337 if(!this.disabled){
26338 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26342 onMouseUp : function(e){
26343 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26348 // backwards compat
26349 Roo.MenuButton = Roo.SplitButton;/*
26351 * Ext JS Library 1.1.1
26352 * Copyright(c) 2006-2007, Ext JS, LLC.
26354 * Originally Released Under LGPL - original licence link has changed is not relivant.
26357 * <script type="text/javascript">
26361 * @class Roo.Toolbar
26362 * Basic Toolbar class.
26364 * Creates a new Toolbar
26365 * @param {Object} config The config object
26367 Roo.Toolbar = function(container, buttons, config)
26369 /// old consturctor format still supported..
26370 if(container instanceof Array){ // omit the container for later rendering
26371 buttons = container;
26375 if (typeof(container) == 'object' && container.xtype) {
26376 config = container;
26377 container = config.container;
26378 buttons = config.buttons; // not really - use items!!
26381 if (config && config.items) {
26382 xitems = config.items;
26383 delete config.items;
26385 Roo.apply(this, config);
26386 this.buttons = buttons;
26389 this.render(container);
26391 Roo.each(xitems, function(b) {
26397 Roo.Toolbar.prototype = {
26399 * @cfg {Roo.data.Store} items
26400 * array of button configs or elements to add
26404 * @cfg {String/HTMLElement/Element} container
26405 * The id or element that will contain the toolbar
26408 render : function(ct){
26409 this.el = Roo.get(ct);
26411 this.el.addClass(this.cls);
26413 // using a table allows for vertical alignment
26414 // 100% width is needed by Safari...
26415 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26416 this.tr = this.el.child("tr", true);
26418 this.items = new Roo.util.MixedCollection(false, function(o){
26419 return o.id || ("item" + (++autoId));
26422 this.add.apply(this, this.buttons);
26423 delete this.buttons;
26428 * Adds element(s) to the toolbar -- this function takes a variable number of
26429 * arguments of mixed type and adds them to the toolbar.
26430 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26432 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26433 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26434 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26435 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26436 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26437 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26438 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26439 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26440 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26442 * @param {Mixed} arg2
26443 * @param {Mixed} etc.
26446 var a = arguments, l = a.length;
26447 for(var i = 0; i < l; i++){
26452 _add : function(el) {
26455 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26458 if (el.applyTo){ // some kind of form field
26459 return this.addField(el);
26461 if (el.render){ // some kind of Toolbar.Item
26462 return this.addItem(el);
26464 if (typeof el == "string"){ // string
26465 if(el == "separator" || el == "-"){
26466 return this.addSeparator();
26469 return this.addSpacer();
26472 return this.addFill();
26474 return this.addText(el);
26477 if(el.tagName){ // element
26478 return this.addElement(el);
26480 if(typeof el == "object"){ // must be button config?
26481 return this.addButton(el);
26483 // and now what?!?!
26489 * Add an Xtype element
26490 * @param {Object} xtype Xtype Object
26491 * @return {Object} created Object
26493 addxtype : function(e){
26494 return this.add(e);
26498 * Returns the Element for this toolbar.
26499 * @return {Roo.Element}
26501 getEl : function(){
26507 * @return {Roo.Toolbar.Item} The separator item
26509 addSeparator : function(){
26510 return this.addItem(new Roo.Toolbar.Separator());
26514 * Adds a spacer element
26515 * @return {Roo.Toolbar.Spacer} The spacer item
26517 addSpacer : function(){
26518 return this.addItem(new Roo.Toolbar.Spacer());
26522 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26523 * @return {Roo.Toolbar.Fill} The fill item
26525 addFill : function(){
26526 return this.addItem(new Roo.Toolbar.Fill());
26530 * Adds any standard HTML element to the toolbar
26531 * @param {String/HTMLElement/Element} el The element or id of the element to add
26532 * @return {Roo.Toolbar.Item} The element's item
26534 addElement : function(el){
26535 return this.addItem(new Roo.Toolbar.Item(el));
26538 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26539 * @type Roo.util.MixedCollection
26544 * Adds any Toolbar.Item or subclass
26545 * @param {Roo.Toolbar.Item} item
26546 * @return {Roo.Toolbar.Item} The item
26548 addItem : function(item){
26549 var td = this.nextBlock();
26551 this.items.add(item);
26556 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26557 * @param {Object/Array} config A button config or array of configs
26558 * @return {Roo.Toolbar.Button/Array}
26560 addButton : function(config){
26561 if(config instanceof Array){
26563 for(var i = 0, len = config.length; i < len; i++) {
26564 buttons.push(this.addButton(config[i]));
26569 if(!(config instanceof Roo.Toolbar.Button)){
26571 new Roo.Toolbar.SplitButton(config) :
26572 new Roo.Toolbar.Button(config);
26574 var td = this.nextBlock();
26581 * Adds text to the toolbar
26582 * @param {String} text The text to add
26583 * @return {Roo.Toolbar.Item} The element's item
26585 addText : function(text){
26586 return this.addItem(new Roo.Toolbar.TextItem(text));
26590 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26591 * @param {Number} index The index where the item is to be inserted
26592 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26593 * @return {Roo.Toolbar.Button/Item}
26595 insertButton : function(index, item){
26596 if(item instanceof Array){
26598 for(var i = 0, len = item.length; i < len; i++) {
26599 buttons.push(this.insertButton(index + i, item[i]));
26603 if (!(item instanceof Roo.Toolbar.Button)){
26604 item = new Roo.Toolbar.Button(item);
26606 var td = document.createElement("td");
26607 this.tr.insertBefore(td, this.tr.childNodes[index]);
26609 this.items.insert(index, item);
26614 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26615 * @param {Object} config
26616 * @return {Roo.Toolbar.Item} The element's item
26618 addDom : function(config, returnEl){
26619 var td = this.nextBlock();
26620 Roo.DomHelper.overwrite(td, config);
26621 var ti = new Roo.Toolbar.Item(td.firstChild);
26623 this.items.add(ti);
26628 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26629 * @type Roo.util.MixedCollection
26634 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26635 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26636 * @param {Roo.form.Field} field
26637 * @return {Roo.ToolbarItem}
26641 addField : function(field) {
26642 if (!this.fields) {
26644 this.fields = new Roo.util.MixedCollection(false, function(o){
26645 return o.id || ("item" + (++autoId));
26650 var td = this.nextBlock();
26652 var ti = new Roo.Toolbar.Item(td.firstChild);
26654 this.items.add(ti);
26655 this.fields.add(field);
26666 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26667 this.el.child('div').hide();
26675 this.el.child('div').show();
26679 nextBlock : function(){
26680 var td = document.createElement("td");
26681 this.tr.appendChild(td);
26686 destroy : function(){
26687 if(this.items){ // rendered?
26688 Roo.destroy.apply(Roo, this.items.items);
26690 if(this.fields){ // rendered?
26691 Roo.destroy.apply(Roo, this.fields.items);
26693 Roo.Element.uncache(this.el, this.tr);
26698 * @class Roo.Toolbar.Item
26699 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26701 * Creates a new Item
26702 * @param {HTMLElement} el
26704 Roo.Toolbar.Item = function(el){
26705 this.el = Roo.getDom(el);
26706 this.id = Roo.id(this.el);
26707 this.hidden = false;
26710 Roo.Toolbar.Item.prototype = {
26713 * Get this item's HTML Element
26714 * @return {HTMLElement}
26716 getEl : function(){
26721 render : function(td){
26723 td.appendChild(this.el);
26727 * Removes and destroys this item.
26729 destroy : function(){
26730 this.td.parentNode.removeChild(this.td);
26737 this.hidden = false;
26738 this.td.style.display = "";
26745 this.hidden = true;
26746 this.td.style.display = "none";
26750 * Convenience function for boolean show/hide.
26751 * @param {Boolean} visible true to show/false to hide
26753 setVisible: function(visible){
26762 * Try to focus this item.
26764 focus : function(){
26765 Roo.fly(this.el).focus();
26769 * Disables this item.
26771 disable : function(){
26772 Roo.fly(this.td).addClass("x-item-disabled");
26773 this.disabled = true;
26774 this.el.disabled = true;
26778 * Enables this item.
26780 enable : function(){
26781 Roo.fly(this.td).removeClass("x-item-disabled");
26782 this.disabled = false;
26783 this.el.disabled = false;
26789 * @class Roo.Toolbar.Separator
26790 * @extends Roo.Toolbar.Item
26791 * A simple toolbar separator class
26793 * Creates a new Separator
26795 Roo.Toolbar.Separator = function(){
26796 var s = document.createElement("span");
26797 s.className = "ytb-sep";
26798 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
26800 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
26801 enable:Roo.emptyFn,
26802 disable:Roo.emptyFn,
26807 * @class Roo.Toolbar.Spacer
26808 * @extends Roo.Toolbar.Item
26809 * A simple element that adds extra horizontal space to a toolbar.
26811 * Creates a new Spacer
26813 Roo.Toolbar.Spacer = function(){
26814 var s = document.createElement("div");
26815 s.className = "ytb-spacer";
26816 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
26818 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
26819 enable:Roo.emptyFn,
26820 disable:Roo.emptyFn,
26825 * @class Roo.Toolbar.Fill
26826 * @extends Roo.Toolbar.Spacer
26827 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
26829 * Creates a new Spacer
26831 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
26833 render : function(td){
26834 td.style.width = '100%';
26835 Roo.Toolbar.Fill.superclass.render.call(this, td);
26840 * @class Roo.Toolbar.TextItem
26841 * @extends Roo.Toolbar.Item
26842 * A simple class that renders text directly into a toolbar.
26844 * Creates a new TextItem
26845 * @param {String} text
26847 Roo.Toolbar.TextItem = function(text){
26848 if (typeof(text) == 'object') {
26851 var s = document.createElement("span");
26852 s.className = "ytb-text";
26853 s.innerHTML = text;
26854 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
26856 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
26857 enable:Roo.emptyFn,
26858 disable:Roo.emptyFn,
26863 * @class Roo.Toolbar.Button
26864 * @extends Roo.Button
26865 * A button that renders into a toolbar.
26867 * Creates a new Button
26868 * @param {Object} config A standard {@link Roo.Button} config object
26870 Roo.Toolbar.Button = function(config){
26871 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
26873 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
26874 render : function(td){
26876 Roo.Toolbar.Button.superclass.render.call(this, td);
26880 * Removes and destroys this button
26882 destroy : function(){
26883 Roo.Toolbar.Button.superclass.destroy.call(this);
26884 this.td.parentNode.removeChild(this.td);
26888 * Shows this button
26891 this.hidden = false;
26892 this.td.style.display = "";
26896 * Hides this button
26899 this.hidden = true;
26900 this.td.style.display = "none";
26904 * Disables this item
26906 disable : function(){
26907 Roo.fly(this.td).addClass("x-item-disabled");
26908 this.disabled = true;
26912 * Enables this item
26914 enable : function(){
26915 Roo.fly(this.td).removeClass("x-item-disabled");
26916 this.disabled = false;
26919 // backwards compat
26920 Roo.ToolbarButton = Roo.Toolbar.Button;
26923 * @class Roo.Toolbar.SplitButton
26924 * @extends Roo.SplitButton
26925 * A menu button that renders into a toolbar.
26927 * Creates a new SplitButton
26928 * @param {Object} config A standard {@link Roo.SplitButton} config object
26930 Roo.Toolbar.SplitButton = function(config){
26931 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
26933 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
26934 render : function(td){
26936 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
26940 * Removes and destroys this button
26942 destroy : function(){
26943 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
26944 this.td.parentNode.removeChild(this.td);
26948 * Shows this button
26951 this.hidden = false;
26952 this.td.style.display = "";
26956 * Hides this button
26959 this.hidden = true;
26960 this.td.style.display = "none";
26964 // backwards compat
26965 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
26967 * Ext JS Library 1.1.1
26968 * Copyright(c) 2006-2007, Ext JS, LLC.
26970 * Originally Released Under LGPL - original licence link has changed is not relivant.
26973 * <script type="text/javascript">
26977 * @class Roo.PagingToolbar
26978 * @extends Roo.Toolbar
26979 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26981 * Create a new PagingToolbar
26982 * @param {Object} config The config object
26984 Roo.PagingToolbar = function(el, ds, config)
26986 // old args format still supported... - xtype is prefered..
26987 if (typeof(el) == 'object' && el.xtype) {
26988 // created from xtype...
26990 ds = el.dataSource;
26991 el = config.container;
26995 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
26998 this.renderButtons(this.el);
27002 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27004 * @cfg {Roo.data.Store} dataSource
27005 * The underlying data store providing the paged data
27008 * @cfg {String/HTMLElement/Element} container
27009 * container The id or element that will contain the toolbar
27012 * @cfg {Boolean} displayInfo
27013 * True to display the displayMsg (defaults to false)
27016 * @cfg {Number} pageSize
27017 * The number of records to display per page (defaults to 20)
27021 * @cfg {String} displayMsg
27022 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27024 displayMsg : 'Displaying {0} - {1} of {2}',
27026 * @cfg {String} emptyMsg
27027 * The message to display when no records are found (defaults to "No data to display")
27029 emptyMsg : 'No data to display',
27031 * Customizable piece of the default paging text (defaults to "Page")
27034 beforePageText : "Page",
27036 * Customizable piece of the default paging text (defaults to "of %0")
27039 afterPageText : "of {0}",
27041 * Customizable piece of the default paging text (defaults to "First Page")
27044 firstText : "First Page",
27046 * Customizable piece of the default paging text (defaults to "Previous Page")
27049 prevText : "Previous Page",
27051 * Customizable piece of the default paging text (defaults to "Next Page")
27054 nextText : "Next Page",
27056 * Customizable piece of the default paging text (defaults to "Last Page")
27059 lastText : "Last Page",
27061 * Customizable piece of the default paging text (defaults to "Refresh")
27064 refreshText : "Refresh",
27067 renderButtons : function(el){
27068 Roo.PagingToolbar.superclass.render.call(this, el);
27069 this.first = this.addButton({
27070 tooltip: this.firstText,
27071 cls: "x-btn-icon x-grid-page-first",
27073 handler: this.onClick.createDelegate(this, ["first"])
27075 this.prev = this.addButton({
27076 tooltip: this.prevText,
27077 cls: "x-btn-icon x-grid-page-prev",
27079 handler: this.onClick.createDelegate(this, ["prev"])
27081 this.addSeparator();
27082 this.add(this.beforePageText);
27083 this.field = Roo.get(this.addDom({
27088 cls: "x-grid-page-number"
27090 this.field.on("keydown", this.onPagingKeydown, this);
27091 this.field.on("focus", function(){this.dom.select();});
27092 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27093 this.field.setHeight(18);
27094 this.addSeparator();
27095 this.next = this.addButton({
27096 tooltip: this.nextText,
27097 cls: "x-btn-icon x-grid-page-next",
27099 handler: this.onClick.createDelegate(this, ["next"])
27101 this.last = this.addButton({
27102 tooltip: this.lastText,
27103 cls: "x-btn-icon x-grid-page-last",
27105 handler: this.onClick.createDelegate(this, ["last"])
27107 this.addSeparator();
27108 this.loading = this.addButton({
27109 tooltip: this.refreshText,
27110 cls: "x-btn-icon x-grid-loading",
27111 handler: this.onClick.createDelegate(this, ["refresh"])
27114 if(this.displayInfo){
27115 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27120 updateInfo : function(){
27121 if(this.displayEl){
27122 var count = this.ds.getCount();
27123 var msg = count == 0 ?
27127 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27129 this.displayEl.update(msg);
27134 onLoad : function(ds, r, o){
27135 this.cursor = o.params ? o.params.start : 0;
27136 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27138 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27139 this.field.dom.value = ap;
27140 this.first.setDisabled(ap == 1);
27141 this.prev.setDisabled(ap == 1);
27142 this.next.setDisabled(ap == ps);
27143 this.last.setDisabled(ap == ps);
27144 this.loading.enable();
27149 getPageData : function(){
27150 var total = this.ds.getTotalCount();
27153 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27154 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27159 onLoadError : function(){
27160 this.loading.enable();
27164 onPagingKeydown : function(e){
27165 var k = e.getKey();
27166 var d = this.getPageData();
27168 var v = this.field.dom.value, pageNum;
27169 if(!v || isNaN(pageNum = parseInt(v, 10))){
27170 this.field.dom.value = d.activePage;
27173 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27174 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27177 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))
27179 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27180 this.field.dom.value = pageNum;
27181 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27184 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27186 var v = this.field.dom.value, pageNum;
27187 var increment = (e.shiftKey) ? 10 : 1;
27188 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27190 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27191 this.field.dom.value = d.activePage;
27194 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27196 this.field.dom.value = parseInt(v, 10) + increment;
27197 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27198 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27205 beforeLoad : function(){
27207 this.loading.disable();
27212 onClick : function(which){
27216 ds.load({params:{start: 0, limit: this.pageSize}});
27219 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27222 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27225 var total = ds.getTotalCount();
27226 var extra = total % this.pageSize;
27227 var lastStart = extra ? (total - extra) : total-this.pageSize;
27228 ds.load({params:{start: lastStart, limit: this.pageSize}});
27231 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27237 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27238 * @param {Roo.data.Store} store The data store to unbind
27240 unbind : function(ds){
27241 ds.un("beforeload", this.beforeLoad, this);
27242 ds.un("load", this.onLoad, this);
27243 ds.un("loadexception", this.onLoadError, this);
27244 ds.un("remove", this.updateInfo, this);
27245 ds.un("add", this.updateInfo, this);
27246 this.ds = undefined;
27250 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27251 * @param {Roo.data.Store} store The data store to bind
27253 bind : function(ds){
27254 ds.on("beforeload", this.beforeLoad, this);
27255 ds.on("load", this.onLoad, this);
27256 ds.on("loadexception", this.onLoadError, this);
27257 ds.on("remove", this.updateInfo, this);
27258 ds.on("add", this.updateInfo, this);
27263 * Ext JS Library 1.1.1
27264 * Copyright(c) 2006-2007, Ext JS, LLC.
27266 * Originally Released Under LGPL - original licence link has changed is not relivant.
27269 * <script type="text/javascript">
27273 * @class Roo.Resizable
27274 * @extends Roo.util.Observable
27275 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27276 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27277 * 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
27278 * the element will be wrapped for you automatically.</p>
27279 * <p>Here is the list of valid resize handles:</p>
27282 ------ -------------------
27293 * <p>Here's an example showing the creation of a typical Resizable:</p>
27295 var resizer = new Roo.Resizable("element-id", {
27303 resizer.on("resize", myHandler);
27305 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27306 * resizer.east.setDisplayed(false);</p>
27307 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27308 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27309 * resize operation's new size (defaults to [0, 0])
27310 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27311 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27312 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27313 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27314 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27315 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27316 * @cfg {Number} width The width of the element in pixels (defaults to null)
27317 * @cfg {Number} height The height of the element in pixels (defaults to null)
27318 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27319 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27320 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27321 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27322 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27323 * in favor of the handles config option (defaults to false)
27324 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27325 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27326 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27327 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27328 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27329 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27330 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27331 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27332 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27333 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27334 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27336 * Create a new resizable component
27337 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27338 * @param {Object} config configuration options
27340 Roo.Resizable = function(el, config){
27341 this.el = Roo.get(el);
27343 if(config && config.wrap){
27344 config.resizeChild = this.el;
27345 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27346 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27347 this.el.setStyle("overflow", "hidden");
27348 this.el.setPositioning(config.resizeChild.getPositioning());
27349 config.resizeChild.clearPositioning();
27350 if(!config.width || !config.height){
27351 var csize = config.resizeChild.getSize();
27352 this.el.setSize(csize.width, csize.height);
27354 if(config.pinned && !config.adjustments){
27355 config.adjustments = "auto";
27359 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27360 this.proxy.unselectable();
27361 this.proxy.enableDisplayMode('block');
27363 Roo.apply(this, config);
27366 this.disableTrackOver = true;
27367 this.el.addClass("x-resizable-pinned");
27369 // if the element isn't positioned, make it relative
27370 var position = this.el.getStyle("position");
27371 if(position != "absolute" && position != "fixed"){
27372 this.el.setStyle("position", "relative");
27374 if(!this.handles){ // no handles passed, must be legacy style
27375 this.handles = 's,e,se';
27376 if(this.multiDirectional){
27377 this.handles += ',n,w';
27380 if(this.handles == "all"){
27381 this.handles = "n s e w ne nw se sw";
27383 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27384 var ps = Roo.Resizable.positions;
27385 for(var i = 0, len = hs.length; i < len; i++){
27386 if(hs[i] && ps[hs[i]]){
27387 var pos = ps[hs[i]];
27388 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27392 this.corner = this.southeast;
27394 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1){
27395 this.updateBox = true;
27398 this.activeHandle = null;
27400 if(this.resizeChild){
27401 if(typeof this.resizeChild == "boolean"){
27402 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27404 this.resizeChild = Roo.get(this.resizeChild, true);
27408 if(this.adjustments == "auto"){
27409 var rc = this.resizeChild;
27410 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27411 if(rc && (hw || hn)){
27412 rc.position("relative");
27413 rc.setLeft(hw ? hw.el.getWidth() : 0);
27414 rc.setTop(hn ? hn.el.getHeight() : 0);
27416 this.adjustments = [
27417 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27418 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27422 if(this.draggable){
27423 this.dd = this.dynamic ?
27424 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27425 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27431 * @event beforeresize
27432 * Fired before resize is allowed. Set enabled to false to cancel resize.
27433 * @param {Roo.Resizable} this
27434 * @param {Roo.EventObject} e The mousedown event
27436 "beforeresize" : true,
27439 * Fired after a resize.
27440 * @param {Roo.Resizable} this
27441 * @param {Number} width The new width
27442 * @param {Number} height The new height
27443 * @param {Roo.EventObject} e The mouseup event
27448 if(this.width !== null && this.height !== null){
27449 this.resizeTo(this.width, this.height);
27451 this.updateChildSize();
27454 this.el.dom.style.zoom = 1;
27456 Roo.Resizable.superclass.constructor.call(this);
27459 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27460 resizeChild : false,
27461 adjustments : [0, 0],
27471 multiDirectional : false,
27472 disableTrackOver : false,
27473 easing : 'easeOutStrong',
27474 widthIncrement : 0,
27475 heightIncrement : 0,
27479 preserveRatio : false,
27480 transparent: false,
27486 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27488 constrainTo: undefined,
27490 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27492 resizeRegion: undefined,
27496 * Perform a manual resize
27497 * @param {Number} width
27498 * @param {Number} height
27500 resizeTo : function(width, height){
27501 this.el.setSize(width, height);
27502 this.updateChildSize();
27503 this.fireEvent("resize", this, width, height, null);
27507 startSizing : function(e, handle){
27508 this.fireEvent("beforeresize", this, e);
27509 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27512 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27513 this.overlay.unselectable();
27514 this.overlay.enableDisplayMode("block");
27515 this.overlay.on("mousemove", this.onMouseMove, this);
27516 this.overlay.on("mouseup", this.onMouseUp, this);
27518 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27520 this.resizing = true;
27521 this.startBox = this.el.getBox();
27522 this.startPoint = e.getXY();
27523 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27524 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27526 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27527 this.overlay.show();
27529 if(this.constrainTo) {
27530 var ct = Roo.get(this.constrainTo);
27531 this.resizeRegion = ct.getRegion().adjust(
27532 ct.getFrameWidth('t'),
27533 ct.getFrameWidth('l'),
27534 -ct.getFrameWidth('b'),
27535 -ct.getFrameWidth('r')
27539 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27541 this.proxy.setBox(this.startBox);
27543 this.proxy.setStyle('visibility', 'visible');
27549 onMouseDown : function(handle, e){
27552 this.activeHandle = handle;
27553 this.startSizing(e, handle);
27558 onMouseUp : function(e){
27559 var size = this.resizeElement();
27560 this.resizing = false;
27562 this.overlay.hide();
27564 this.fireEvent("resize", this, size.width, size.height, e);
27568 updateChildSize : function(){
27569 if(this.resizeChild){
27571 var child = this.resizeChild;
27572 var adj = this.adjustments;
27573 if(el.dom.offsetWidth){
27574 var b = el.getSize(true);
27575 child.setSize(b.width+adj[0], b.height+adj[1]);
27577 // Second call here for IE
27578 // The first call enables instant resizing and
27579 // the second call corrects scroll bars if they
27582 setTimeout(function(){
27583 if(el.dom.offsetWidth){
27584 var b = el.getSize(true);
27585 child.setSize(b.width+adj[0], b.height+adj[1]);
27593 snap : function(value, inc, min){
27594 if(!inc || !value) return value;
27595 var newValue = value;
27596 var m = value % inc;
27599 newValue = value + (inc-m);
27601 newValue = value - m;
27604 return Math.max(min, newValue);
27608 resizeElement : function(){
27609 var box = this.proxy.getBox();
27610 if(this.updateBox){
27611 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27613 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27615 this.updateChildSize();
27623 constrain : function(v, diff, m, mx){
27626 }else if(v - diff > mx){
27633 onMouseMove : function(e){
27635 try{// try catch so if something goes wrong the user doesn't get hung
27637 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27641 //var curXY = this.startPoint;
27642 var curSize = this.curSize || this.startBox;
27643 var x = this.startBox.x, y = this.startBox.y;
27644 var ox = x, oy = y;
27645 var w = curSize.width, h = curSize.height;
27646 var ow = w, oh = h;
27647 var mw = this.minWidth, mh = this.minHeight;
27648 var mxw = this.maxWidth, mxh = this.maxHeight;
27649 var wi = this.widthIncrement;
27650 var hi = this.heightIncrement;
27652 var eventXY = e.getXY();
27653 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27654 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27656 var pos = this.activeHandle.position;
27661 w = Math.min(Math.max(mw, w), mxw);
27665 h = Math.min(Math.max(mh, h), mxh);
27670 w = Math.min(Math.max(mw, w), mxw);
27671 h = Math.min(Math.max(mh, h), mxh);
27674 diffY = this.constrain(h, diffY, mh, mxh);
27679 diffX = this.constrain(w, diffX, mw, mxw);
27685 w = Math.min(Math.max(mw, w), mxw);
27686 diffY = this.constrain(h, diffY, mh, mxh);
27691 diffX = this.constrain(w, diffX, mw, mxw);
27692 diffY = this.constrain(h, diffY, mh, mxh);
27699 diffX = this.constrain(w, diffX, mw, mxw);
27701 h = Math.min(Math.max(mh, h), mxh);
27707 var sw = this.snap(w, wi, mw);
27708 var sh = this.snap(h, hi, mh);
27709 if(sw != w || sh != h){
27732 if(this.preserveRatio){
27737 h = Math.min(Math.max(mh, h), mxh);
27742 w = Math.min(Math.max(mw, w), mxw);
27747 w = Math.min(Math.max(mw, w), mxw);
27753 w = Math.min(Math.max(mw, w), mxw);
27759 h = Math.min(Math.max(mh, h), mxh);
27767 h = Math.min(Math.max(mh, h), mxh);
27777 h = Math.min(Math.max(mh, h), mxh);
27785 this.proxy.setBounds(x, y, w, h);
27787 this.resizeElement();
27794 handleOver : function(){
27796 this.el.addClass("x-resizable-over");
27801 handleOut : function(){
27802 if(!this.resizing){
27803 this.el.removeClass("x-resizable-over");
27808 * Returns the element this component is bound to.
27809 * @return {Roo.Element}
27811 getEl : function(){
27816 * Returns the resizeChild element (or null).
27817 * @return {Roo.Element}
27819 getResizeChild : function(){
27820 return this.resizeChild;
27824 * Destroys this resizable. If the element was wrapped and
27825 * removeEl is not true then the element remains.
27826 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
27828 destroy : function(removeEl){
27829 this.proxy.remove();
27831 this.overlay.removeAllListeners();
27832 this.overlay.remove();
27834 var ps = Roo.Resizable.positions;
27836 if(typeof ps[k] != "function" && this[ps[k]]){
27837 var h = this[ps[k]];
27838 h.el.removeAllListeners();
27843 this.el.update("");
27850 // hash to map config positions to true positions
27851 Roo.Resizable.positions = {
27852 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast"
27856 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
27858 // only initialize the template if resizable is used
27859 var tpl = Roo.DomHelper.createTemplate(
27860 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
27863 Roo.Resizable.Handle.prototype.tpl = tpl;
27865 this.position = pos;
27867 this.el = this.tpl.append(rz.el.dom, [this.position], true);
27868 this.el.unselectable();
27870 this.el.setOpacity(0);
27872 this.el.on("mousedown", this.onMouseDown, this);
27873 if(!disableTrackOver){
27874 this.el.on("mouseover", this.onMouseOver, this);
27875 this.el.on("mouseout", this.onMouseOut, this);
27880 Roo.Resizable.Handle.prototype = {
27881 afterResize : function(rz){
27885 onMouseDown : function(e){
27886 this.rz.onMouseDown(this, e);
27889 onMouseOver : function(e){
27890 this.rz.handleOver(this, e);
27893 onMouseOut : function(e){
27894 this.rz.handleOut(this, e);
27898 * Ext JS Library 1.1.1
27899 * Copyright(c) 2006-2007, Ext JS, LLC.
27901 * Originally Released Under LGPL - original licence link has changed is not relivant.
27904 * <script type="text/javascript">
27908 * @class Roo.Editor
27909 * @extends Roo.Component
27910 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
27912 * Create a new Editor
27913 * @param {Roo.form.Field} field The Field object (or descendant)
27914 * @param {Object} config The config object
27916 Roo.Editor = function(field, config){
27917 Roo.Editor.superclass.constructor.call(this, config);
27918 this.field = field;
27921 * @event beforestartedit
27922 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
27923 * false from the handler of this event.
27924 * @param {Editor} this
27925 * @param {Roo.Element} boundEl The underlying element bound to this editor
27926 * @param {Mixed} value The field value being set
27928 "beforestartedit" : true,
27931 * Fires when this editor is displayed
27932 * @param {Roo.Element} boundEl The underlying element bound to this editor
27933 * @param {Mixed} value The starting field value
27935 "startedit" : true,
27937 * @event beforecomplete
27938 * Fires after a change has been made to the field, but before the change is reflected in the underlying
27939 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
27940 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
27941 * event will not fire since no edit actually occurred.
27942 * @param {Editor} this
27943 * @param {Mixed} value The current field value
27944 * @param {Mixed} startValue The original field value
27946 "beforecomplete" : true,
27949 * Fires after editing is complete and any changed value has been written to the underlying field.
27950 * @param {Editor} this
27951 * @param {Mixed} value The current field value
27952 * @param {Mixed} startValue The original field value
27956 * @event specialkey
27957 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
27958 * {@link Roo.EventObject#getKey} to determine which key was pressed.
27959 * @param {Roo.form.Field} this
27960 * @param {Roo.EventObject} e The event object
27962 "specialkey" : true
27966 Roo.extend(Roo.Editor, Roo.Component, {
27968 * @cfg {Boolean/String} autosize
27969 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
27970 * or "height" to adopt the height only (defaults to false)
27973 * @cfg {Boolean} revertInvalid
27974 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
27975 * validation fails (defaults to true)
27978 * @cfg {Boolean} ignoreNoChange
27979 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
27980 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
27981 * will never be ignored.
27984 * @cfg {Boolean} hideEl
27985 * False to keep the bound element visible while the editor is displayed (defaults to true)
27988 * @cfg {Mixed} value
27989 * The data value of the underlying field (defaults to "")
27993 * @cfg {String} alignment
27994 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
27998 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
27999 * for bottom-right shadow (defaults to "frame")
28003 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28007 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28009 completeOnEnter : false,
28011 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28013 cancelOnEsc : false,
28015 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28020 onRender : function(ct, position){
28021 this.el = new Roo.Layer({
28022 shadow: this.shadow,
28028 constrain: this.constrain
28030 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28031 if(this.field.msgTarget != 'title'){
28032 this.field.msgTarget = 'qtip';
28034 this.field.render(this.el);
28036 this.field.el.dom.setAttribute('autocomplete', 'off');
28038 this.field.on("specialkey", this.onSpecialKey, this);
28039 if(this.swallowKeys){
28040 this.field.el.swallowEvent(['keydown','keypress']);
28043 this.field.on("blur", this.onBlur, this);
28044 if(this.field.grow){
28045 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28049 onSpecialKey : function(field, e){
28050 if(this.completeOnEnter && e.getKey() == e.ENTER){
28052 this.completeEdit();
28053 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
28056 this.fireEvent('specialkey', field, e);
28061 * Starts the editing process and shows the editor.
28062 * @param {String/HTMLElement/Element} el The element to edit
28063 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28064 * to the innerHTML of el.
28066 startEdit : function(el, value){
28068 this.completeEdit();
28070 this.boundEl = Roo.get(el);
28071 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28072 if(!this.rendered){
28073 this.render(this.parentEl || document.body);
28075 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28078 this.startValue = v;
28079 this.field.setValue(v);
28081 var sz = this.boundEl.getSize();
28082 switch(this.autoSize){
28084 this.setSize(sz.width, "");
28087 this.setSize("", sz.height);
28090 this.setSize(sz.width, sz.height);
28093 this.el.alignTo(this.boundEl, this.alignment);
28094 this.editing = true;
28096 Roo.QuickTips.disable();
28102 * Sets the height and width of this editor.
28103 * @param {Number} width The new width
28104 * @param {Number} height The new height
28106 setSize : function(w, h){
28107 this.field.setSize(w, h);
28114 * Realigns the editor to the bound field based on the current alignment config value.
28116 realign : function(){
28117 this.el.alignTo(this.boundEl, this.alignment);
28121 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28122 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28124 completeEdit : function(remainVisible){
28128 var v = this.getValue();
28129 if(this.revertInvalid !== false && !this.field.isValid()){
28130 v = this.startValue;
28131 this.cancelEdit(true);
28133 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28134 this.editing = false;
28138 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28139 this.editing = false;
28140 if(this.updateEl && this.boundEl){
28141 this.boundEl.update(v);
28143 if(remainVisible !== true){
28146 this.fireEvent("complete", this, v, this.startValue);
28151 onShow : function(){
28153 if(this.hideEl !== false){
28154 this.boundEl.hide();
28157 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28158 this.fixIEFocus = true;
28159 this.deferredFocus.defer(50, this);
28161 this.field.focus();
28163 this.fireEvent("startedit", this.boundEl, this.startValue);
28166 deferredFocus : function(){
28168 this.field.focus();
28173 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28174 * reverted to the original starting value.
28175 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28176 * cancel (defaults to false)
28178 cancelEdit : function(remainVisible){
28180 this.setValue(this.startValue);
28181 if(remainVisible !== true){
28188 onBlur : function(){
28189 if(this.allowBlur !== true && this.editing){
28190 this.completeEdit();
28195 onHide : function(){
28197 this.completeEdit();
28201 if(this.field.collapse){
28202 this.field.collapse();
28205 if(this.hideEl !== false){
28206 this.boundEl.show();
28209 Roo.QuickTips.enable();
28214 * Sets the data value of the editor
28215 * @param {Mixed} value Any valid value supported by the underlying field
28217 setValue : function(v){
28218 this.field.setValue(v);
28222 * Gets the data value of the editor
28223 * @return {Mixed} The data value
28225 getValue : function(){
28226 return this.field.getValue();
28230 * Ext JS Library 1.1.1
28231 * Copyright(c) 2006-2007, Ext JS, LLC.
28233 * Originally Released Under LGPL - original licence link has changed is not relivant.
28236 * <script type="text/javascript">
28240 * @class Roo.BasicDialog
28241 * @extends Roo.util.Observable
28242 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28244 var dlg = new Roo.BasicDialog("my-dlg", {
28253 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28254 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28255 dlg.addButton('Cancel', dlg.hide, dlg);
28258 <b>A Dialog should always be a direct child of the body element.</b>
28259 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28260 * @cfg {String} title Default text to display in the title bar (defaults to null)
28261 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28262 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28263 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28264 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28265 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28266 * (defaults to null with no animation)
28267 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28268 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28269 * property for valid values (defaults to 'all')
28270 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28271 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28272 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28273 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28274 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28275 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28276 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28277 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28278 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28279 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28280 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28281 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28282 * draggable = true (defaults to false)
28283 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28284 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28285 * shadow (defaults to false)
28286 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28287 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28288 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28289 * @cfg {Array} buttons Array of buttons
28290 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28292 * Create a new BasicDialog.
28293 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28294 * @param {Object} config Configuration options
28296 Roo.BasicDialog = function(el, config){
28297 this.el = Roo.get(el);
28298 var dh = Roo.DomHelper;
28299 if(!this.el && config && config.autoCreate){
28300 if(typeof config.autoCreate == "object"){
28301 if(!config.autoCreate.id){
28302 config.autoCreate.id = el;
28304 this.el = dh.append(document.body,
28305 config.autoCreate, true);
28307 this.el = dh.append(document.body,
28308 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28312 el.setDisplayed(true);
28313 el.hide = this.hideAction;
28315 el.addClass("x-dlg");
28317 Roo.apply(this, config);
28319 this.proxy = el.createProxy("x-dlg-proxy");
28320 this.proxy.hide = this.hideAction;
28321 this.proxy.setOpacity(.5);
28325 el.setWidth(config.width);
28328 el.setHeight(config.height);
28330 this.size = el.getSize();
28331 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28332 this.xy = [config.x,config.y];
28334 this.xy = el.getCenterXY(true);
28336 /** The header element @type Roo.Element */
28337 this.header = el.child("> .x-dlg-hd");
28338 /** The body element @type Roo.Element */
28339 this.body = el.child("> .x-dlg-bd");
28340 /** The footer element @type Roo.Element */
28341 this.footer = el.child("> .x-dlg-ft");
28344 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28347 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28350 this.header.unselectable();
28352 this.header.update(this.title);
28354 // this element allows the dialog to be focused for keyboard event
28355 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28356 this.focusEl.swallowEvent("click", true);
28358 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28360 // wrap the body and footer for special rendering
28361 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28363 this.bwrap.dom.appendChild(this.footer.dom);
28366 this.bg = this.el.createChild({
28367 tag: "div", cls:"x-dlg-bg",
28368 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28370 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28373 if(this.autoScroll !== false && !this.autoTabs){
28374 this.body.setStyle("overflow", "auto");
28377 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28379 if(this.closable !== false){
28380 this.el.addClass("x-dlg-closable");
28381 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28382 this.close.on("click", this.closeClick, this);
28383 this.close.addClassOnOver("x-dlg-close-over");
28385 if(this.collapsible !== false){
28386 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28387 this.collapseBtn.on("click", this.collapseClick, this);
28388 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28389 this.header.on("dblclick", this.collapseClick, this);
28391 if(this.resizable !== false){
28392 this.el.addClass("x-dlg-resizable");
28393 this.resizer = new Roo.Resizable(el, {
28394 minWidth: this.minWidth || 80,
28395 minHeight:this.minHeight || 80,
28396 handles: this.resizeHandles || "all",
28399 this.resizer.on("beforeresize", this.beforeResize, this);
28400 this.resizer.on("resize", this.onResize, this);
28402 if(this.draggable !== false){
28403 el.addClass("x-dlg-draggable");
28404 if (!this.proxyDrag) {
28405 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28408 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28410 dd.setHandleElId(this.header.id);
28411 dd.endDrag = this.endMove.createDelegate(this);
28412 dd.startDrag = this.startMove.createDelegate(this);
28413 dd.onDrag = this.onDrag.createDelegate(this);
28418 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28419 this.mask.enableDisplayMode("block");
28421 this.el.addClass("x-dlg-modal");
28424 this.shadow = new Roo.Shadow({
28425 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28426 offset : this.shadowOffset
28429 this.shadowOffset = 0;
28431 if(Roo.useShims && this.shim !== false){
28432 this.shim = this.el.createShim();
28433 this.shim.hide = this.hideAction;
28441 if (this.buttons) {
28442 var bts= this.buttons;
28444 Roo.each(bts, function(b) {
28453 * Fires when a key is pressed
28454 * @param {Roo.BasicDialog} this
28455 * @param {Roo.EventObject} e
28460 * Fires when this dialog is moved by the user.
28461 * @param {Roo.BasicDialog} this
28462 * @param {Number} x The new page X
28463 * @param {Number} y The new page Y
28468 * Fires when this dialog is resized by the user.
28469 * @param {Roo.BasicDialog} this
28470 * @param {Number} width The new width
28471 * @param {Number} height The new height
28475 * @event beforehide
28476 * Fires before this dialog is hidden.
28477 * @param {Roo.BasicDialog} this
28479 "beforehide" : true,
28482 * Fires when this dialog is hidden.
28483 * @param {Roo.BasicDialog} this
28487 * @event beforeshow
28488 * Fires before this dialog is shown.
28489 * @param {Roo.BasicDialog} this
28491 "beforeshow" : true,
28494 * Fires when this dialog is shown.
28495 * @param {Roo.BasicDialog} this
28499 el.on("keydown", this.onKeyDown, this);
28500 el.on("mousedown", this.toFront, this);
28501 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28503 Roo.DialogManager.register(this);
28504 Roo.BasicDialog.superclass.constructor.call(this);
28507 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28508 shadowOffset: Roo.isIE ? 6 : 5,
28511 minButtonWidth: 75,
28512 defaultButton: null,
28513 buttonAlign: "right",
28518 * Sets the dialog title text
28519 * @param {String} text The title text to display
28520 * @return {Roo.BasicDialog} this
28522 setTitle : function(text){
28523 this.header.update(text);
28528 closeClick : function(){
28533 collapseClick : function(){
28534 this[this.collapsed ? "expand" : "collapse"]();
28538 * Collapses the dialog to its minimized state (only the title bar is visible).
28539 * Equivalent to the user clicking the collapse dialog button.
28541 collapse : function(){
28542 if(!this.collapsed){
28543 this.collapsed = true;
28544 this.el.addClass("x-dlg-collapsed");
28545 this.restoreHeight = this.el.getHeight();
28546 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28551 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28552 * clicking the expand dialog button.
28554 expand : function(){
28555 if(this.collapsed){
28556 this.collapsed = false;
28557 this.el.removeClass("x-dlg-collapsed");
28558 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28563 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28564 * @return {Roo.TabPanel} The tabs component
28566 initTabs : function(){
28567 var tabs = this.getTabs();
28568 while(tabs.getTab(0)){
28571 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28573 tabs.addTab(Roo.id(dom), dom.title);
28581 beforeResize : function(){
28582 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28586 onResize : function(){
28587 this.refreshSize();
28588 this.syncBodyHeight();
28589 this.adjustAssets();
28591 this.fireEvent("resize", this, this.size.width, this.size.height);
28595 onKeyDown : function(e){
28596 if(this.isVisible()){
28597 this.fireEvent("keydown", this, e);
28602 * Resizes the dialog.
28603 * @param {Number} width
28604 * @param {Number} height
28605 * @return {Roo.BasicDialog} this
28607 resizeTo : function(width, height){
28608 this.el.setSize(width, height);
28609 this.size = {width: width, height: height};
28610 this.syncBodyHeight();
28611 if(this.fixedcenter){
28614 if(this.isVisible()){
28615 this.constrainXY();
28616 this.adjustAssets();
28618 this.fireEvent("resize", this, width, height);
28624 * Resizes the dialog to fit the specified content size.
28625 * @param {Number} width
28626 * @param {Number} height
28627 * @return {Roo.BasicDialog} this
28629 setContentSize : function(w, h){
28630 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28631 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28632 //if(!this.el.isBorderBox()){
28633 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28634 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28637 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28638 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28640 this.resizeTo(w, h);
28645 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28646 * executed in response to a particular key being pressed while the dialog is active.
28647 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28648 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28649 * @param {Function} fn The function to call
28650 * @param {Object} scope (optional) The scope of the function
28651 * @return {Roo.BasicDialog} this
28653 addKeyListener : function(key, fn, scope){
28654 var keyCode, shift, ctrl, alt;
28655 if(typeof key == "object" && !(key instanceof Array)){
28656 keyCode = key["key"];
28657 shift = key["shift"];
28658 ctrl = key["ctrl"];
28663 var handler = function(dlg, e){
28664 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28665 var k = e.getKey();
28666 if(keyCode instanceof Array){
28667 for(var i = 0, len = keyCode.length; i < len; i++){
28668 if(keyCode[i] == k){
28669 fn.call(scope || window, dlg, k, e);
28675 fn.call(scope || window, dlg, k, e);
28680 this.on("keydown", handler);
28685 * Returns the TabPanel component (creates it if it doesn't exist).
28686 * Note: If you wish to simply check for the existence of tabs without creating them,
28687 * check for a null 'tabs' property.
28688 * @return {Roo.TabPanel} The tabs component
28690 getTabs : function(){
28692 this.el.addClass("x-dlg-auto-tabs");
28693 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28694 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28700 * Adds a button to the footer section of the dialog.
28701 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28702 * object or a valid Roo.DomHelper element config
28703 * @param {Function} handler The function called when the button is clicked
28704 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28705 * @return {Roo.Button} The new button
28707 addButton : function(config, handler, scope){
28708 var dh = Roo.DomHelper;
28710 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28712 if(!this.btnContainer){
28713 var tb = this.footer.createChild({
28715 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28716 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28718 this.btnContainer = tb.firstChild.firstChild.firstChild;
28723 minWidth: this.minButtonWidth,
28726 if(typeof config == "string"){
28727 bconfig.text = config;
28730 bconfig.dhconfig = config;
28732 Roo.apply(bconfig, config);
28736 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28737 bconfig.position = Math.max(0, bconfig.position);
28738 fc = this.btnContainer.childNodes[bconfig.position];
28741 var btn = new Roo.Button(
28743 this.btnContainer.insertBefore(document.createElement("td"),fc)
28744 : this.btnContainer.appendChild(document.createElement("td")),
28745 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
28748 this.syncBodyHeight();
28751 * Array of all the buttons that have been added to this dialog via addButton
28756 this.buttons.push(btn);
28761 * Sets the default button to be focused when the dialog is displayed.
28762 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
28763 * @return {Roo.BasicDialog} this
28765 setDefaultButton : function(btn){
28766 this.defaultButton = btn;
28771 getHeaderFooterHeight : function(safe){
28774 height += this.header.getHeight();
28777 var fm = this.footer.getMargins();
28778 height += (this.footer.getHeight()+fm.top+fm.bottom);
28780 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
28781 height += this.centerBg.getPadding("tb");
28786 syncBodyHeight : function(){
28787 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
28788 var height = this.size.height - this.getHeaderFooterHeight(false);
28789 bd.setHeight(height-bd.getMargins("tb"));
28790 var hh = this.header.getHeight();
28791 var h = this.size.height-hh;
28793 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
28794 bw.setHeight(h-cb.getPadding("tb"));
28795 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
28796 bd.setWidth(bw.getWidth(true));
28798 this.tabs.syncHeight();
28800 this.tabs.el.repaint();
28806 * Restores the previous state of the dialog if Roo.state is configured.
28807 * @return {Roo.BasicDialog} this
28809 restoreState : function(){
28810 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
28811 if(box && box.width){
28812 this.xy = [box.x, box.y];
28813 this.resizeTo(box.width, box.height);
28819 beforeShow : function(){
28821 if(this.fixedcenter){
28822 this.xy = this.el.getCenterXY(true);
28825 Roo.get(document.body).addClass("x-body-masked");
28826 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28829 this.constrainXY();
28833 animShow : function(){
28834 var b = Roo.get(this.animateTarget, true).getBox();
28835 this.proxy.setSize(b.width, b.height);
28836 this.proxy.setLocation(b.x, b.y);
28838 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
28839 true, .35, this.showEl.createDelegate(this));
28843 * Shows the dialog.
28844 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
28845 * @return {Roo.BasicDialog} this
28847 show : function(animateTarget){
28848 if (this.fireEvent("beforeshow", this) === false){
28851 if(this.syncHeightBeforeShow){
28852 this.syncBodyHeight();
28853 }else if(this.firstShow){
28854 this.firstShow = false;
28855 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
28857 this.animateTarget = animateTarget || this.animateTarget;
28858 if(!this.el.isVisible()){
28860 if(this.animateTarget){
28870 showEl : function(){
28872 this.el.setXY(this.xy);
28874 this.adjustAssets(true);
28877 // IE peekaboo bug - fix found by Dave Fenwick
28881 this.fireEvent("show", this);
28885 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
28886 * dialog itself will receive focus.
28888 focus : function(){
28889 if(this.defaultButton){
28890 this.defaultButton.focus();
28892 this.focusEl.focus();
28897 constrainXY : function(){
28898 if(this.constraintoviewport !== false){
28899 if(!this.viewSize){
28900 if(this.container){
28901 var s = this.container.getSize();
28902 this.viewSize = [s.width, s.height];
28904 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
28907 var s = Roo.get(this.container||document).getScroll();
28909 var x = this.xy[0], y = this.xy[1];
28910 var w = this.size.width, h = this.size.height;
28911 var vw = this.viewSize[0], vh = this.viewSize[1];
28912 // only move it if it needs it
28914 // first validate right/bottom
28915 if(x + w > vw+s.left){
28919 if(y + h > vh+s.top){
28923 // then make sure top/left isn't negative
28935 if(this.isVisible()){
28936 this.el.setLocation(x, y);
28937 this.adjustAssets();
28944 onDrag : function(){
28945 if(!this.proxyDrag){
28946 this.xy = this.el.getXY();
28947 this.adjustAssets();
28952 adjustAssets : function(doShow){
28953 var x = this.xy[0], y = this.xy[1];
28954 var w = this.size.width, h = this.size.height;
28955 if(doShow === true){
28957 this.shadow.show(this.el);
28963 if(this.shadow && this.shadow.isVisible()){
28964 this.shadow.show(this.el);
28966 if(this.shim && this.shim.isVisible()){
28967 this.shim.setBounds(x, y, w, h);
28972 adjustViewport : function(w, h){
28974 w = Roo.lib.Dom.getViewWidth();
28975 h = Roo.lib.Dom.getViewHeight();
28978 this.viewSize = [w, h];
28979 if(this.modal && this.mask.isVisible()){
28980 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
28981 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28983 if(this.isVisible()){
28984 this.constrainXY();
28989 * Destroys this dialog and all its supporting elements (including any tabs, shim,
28990 * shadow, proxy, mask, etc.) Also removes all event listeners.
28991 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28993 destroy : function(removeEl){
28994 if(this.isVisible()){
28995 this.animateTarget = null;
28998 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29000 this.tabs.destroy(removeEl);
29013 for(var i = 0, len = this.buttons.length; i < len; i++){
29014 this.buttons[i].destroy();
29017 this.el.removeAllListeners();
29018 if(removeEl === true){
29019 this.el.update("");
29022 Roo.DialogManager.unregister(this);
29026 startMove : function(){
29027 if(this.proxyDrag){
29030 if(this.constraintoviewport !== false){
29031 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29036 endMove : function(){
29037 if(!this.proxyDrag){
29038 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29040 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29043 this.refreshSize();
29044 this.adjustAssets();
29046 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29050 * Brings this dialog to the front of any other visible dialogs
29051 * @return {Roo.BasicDialog} this
29053 toFront : function(){
29054 Roo.DialogManager.bringToFront(this);
29059 * Sends this dialog to the back (under) of any other visible dialogs
29060 * @return {Roo.BasicDialog} this
29062 toBack : function(){
29063 Roo.DialogManager.sendToBack(this);
29068 * Centers this dialog in the viewport
29069 * @return {Roo.BasicDialog} this
29071 center : function(){
29072 var xy = this.el.getCenterXY(true);
29073 this.moveTo(xy[0], xy[1]);
29078 * Moves the dialog's top-left corner to the specified point
29079 * @param {Number} x
29080 * @param {Number} y
29081 * @return {Roo.BasicDialog} this
29083 moveTo : function(x, y){
29085 if(this.isVisible()){
29086 this.el.setXY(this.xy);
29087 this.adjustAssets();
29093 * Aligns the dialog to the specified element
29094 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29095 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29096 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29097 * @return {Roo.BasicDialog} this
29099 alignTo : function(element, position, offsets){
29100 this.xy = this.el.getAlignToXY(element, position, offsets);
29101 if(this.isVisible()){
29102 this.el.setXY(this.xy);
29103 this.adjustAssets();
29109 * Anchors an element to another element and realigns it when the window is resized.
29110 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29111 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29112 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29113 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29114 * is a number, it is used as the buffer delay (defaults to 50ms).
29115 * @return {Roo.BasicDialog} this
29117 anchorTo : function(el, alignment, offsets, monitorScroll){
29118 var action = function(){
29119 this.alignTo(el, alignment, offsets);
29121 Roo.EventManager.onWindowResize(action, this);
29122 var tm = typeof monitorScroll;
29123 if(tm != 'undefined'){
29124 Roo.EventManager.on(window, 'scroll', action, this,
29125 {buffer: tm == 'number' ? monitorScroll : 50});
29132 * Returns true if the dialog is visible
29133 * @return {Boolean}
29135 isVisible : function(){
29136 return this.el.isVisible();
29140 animHide : function(callback){
29141 var b = Roo.get(this.animateTarget).getBox();
29143 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29145 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29146 this.hideEl.createDelegate(this, [callback]));
29150 * Hides the dialog.
29151 * @param {Function} callback (optional) Function to call when the dialog is hidden
29152 * @return {Roo.BasicDialog} this
29154 hide : function(callback){
29155 if (this.fireEvent("beforehide", this) === false){
29159 this.shadow.hide();
29164 if(this.animateTarget){
29165 this.animHide(callback);
29168 this.hideEl(callback);
29174 hideEl : function(callback){
29178 Roo.get(document.body).removeClass("x-body-masked");
29180 this.fireEvent("hide", this);
29181 if(typeof callback == "function"){
29187 hideAction : function(){
29188 this.setLeft("-10000px");
29189 this.setTop("-10000px");
29190 this.setStyle("visibility", "hidden");
29194 refreshSize : function(){
29195 this.size = this.el.getSize();
29196 this.xy = this.el.getXY();
29197 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29201 // z-index is managed by the DialogManager and may be overwritten at any time
29202 setZIndex : function(index){
29204 this.mask.setStyle("z-index", index);
29207 this.shim.setStyle("z-index", ++index);
29210 this.shadow.setZIndex(++index);
29212 this.el.setStyle("z-index", ++index);
29214 this.proxy.setStyle("z-index", ++index);
29217 this.resizer.proxy.setStyle("z-index", ++index);
29220 this.lastZIndex = index;
29224 * Returns the element for this dialog
29225 * @return {Roo.Element} The underlying dialog Element
29227 getEl : function(){
29233 * @class Roo.DialogManager
29234 * Provides global access to BasicDialogs that have been created and
29235 * support for z-indexing (layering) multiple open dialogs.
29237 Roo.DialogManager = function(){
29239 var accessList = [];
29243 var sortDialogs = function(d1, d2){
29244 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29248 var orderDialogs = function(){
29249 accessList.sort(sortDialogs);
29250 var seed = Roo.DialogManager.zseed;
29251 for(var i = 0, len = accessList.length; i < len; i++){
29252 var dlg = accessList[i];
29254 dlg.setZIndex(seed + (i*10));
29261 * The starting z-index for BasicDialogs (defaults to 9000)
29262 * @type Number The z-index value
29267 register : function(dlg){
29268 list[dlg.id] = dlg;
29269 accessList.push(dlg);
29273 unregister : function(dlg){
29274 delete list[dlg.id];
29277 if(!accessList.indexOf){
29278 for( i = 0, len = accessList.length; i < len; i++){
29279 if(accessList[i] == dlg){
29280 accessList.splice(i, 1);
29285 i = accessList.indexOf(dlg);
29287 accessList.splice(i, 1);
29293 * Gets a registered dialog by id
29294 * @param {String/Object} id The id of the dialog or a dialog
29295 * @return {Roo.BasicDialog} this
29297 get : function(id){
29298 return typeof id == "object" ? id : list[id];
29302 * Brings the specified dialog to the front
29303 * @param {String/Object} dlg The id of the dialog or a dialog
29304 * @return {Roo.BasicDialog} this
29306 bringToFront : function(dlg){
29307 dlg = this.get(dlg);
29310 dlg._lastAccess = new Date().getTime();
29317 * Sends the specified dialog to the back
29318 * @param {String/Object} dlg The id of the dialog or a dialog
29319 * @return {Roo.BasicDialog} this
29321 sendToBack : function(dlg){
29322 dlg = this.get(dlg);
29323 dlg._lastAccess = -(new Date().getTime());
29329 * Hides all dialogs
29331 hideAll : function(){
29332 for(var id in list){
29333 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29342 * @class Roo.LayoutDialog
29343 * @extends Roo.BasicDialog
29344 * Dialog which provides adjustments for working with a layout in a Dialog.
29345 * Add your necessary layout config options to the dialog's config.<br>
29346 * Example usage (including a nested layout):
29349 dialog = new Roo.LayoutDialog("download-dlg", {
29358 // layout config merges with the dialog config
29360 tabPosition: "top",
29361 alwaysShowTabs: true
29364 dialog.addKeyListener(27, dialog.hide, dialog);
29365 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29366 dialog.addButton("Build It!", this.getDownload, this);
29368 // we can even add nested layouts
29369 var innerLayout = new Roo.BorderLayout("dl-inner", {
29379 innerLayout.beginUpdate();
29380 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29381 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29382 innerLayout.endUpdate(true);
29384 var layout = dialog.getLayout();
29385 layout.beginUpdate();
29386 layout.add("center", new Roo.ContentPanel("standard-panel",
29387 {title: "Download the Source", fitToFrame:true}));
29388 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29389 {title: "Build your own roo.js"}));
29390 layout.getRegion("center").showPanel(sp);
29391 layout.endUpdate();
29395 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29396 * @param {Object} config configuration options
29398 Roo.LayoutDialog = function(el, cfg){
29401 if (typeof(cfg) == 'undefined') {
29402 config = Roo.apply({}, el);
29403 el = Roo.get( document.documentElement || document.body).createChild();
29404 //config.autoCreate = true;
29408 config.autoTabs = false;
29409 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29410 this.body.setStyle({overflow:"hidden", position:"relative"});
29411 this.layout = new Roo.BorderLayout(this.body.dom, config);
29412 this.layout.monitorWindowResize = false;
29413 this.el.addClass("x-dlg-auto-layout");
29414 // fix case when center region overwrites center function
29415 this.center = Roo.BasicDialog.prototype.center;
29416 this.on("show", this.layout.layout, this.layout, true);
29417 if (config.items) {
29418 var xitems = config.items;
29419 delete config.items;
29420 Roo.each(xitems, this.addxtype, this);
29425 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29427 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29430 endUpdate : function(){
29431 this.layout.endUpdate();
29435 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29438 beginUpdate : function(){
29439 this.layout.beginUpdate();
29443 * Get the BorderLayout for this dialog
29444 * @return {Roo.BorderLayout}
29446 getLayout : function(){
29447 return this.layout;
29450 showEl : function(){
29451 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29453 this.layout.layout();
29458 // Use the syncHeightBeforeShow config option to control this automatically
29459 syncBodyHeight : function(){
29460 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29461 if(this.layout){this.layout.layout();}
29465 * Add an xtype element (actually adds to the layout.)
29466 * @return {Object} xdata xtype object data.
29469 addxtype : function(c) {
29470 return this.layout.addxtype(c);
29474 * Ext JS Library 1.1.1
29475 * Copyright(c) 2006-2007, Ext JS, LLC.
29477 * Originally Released Under LGPL - original licence link has changed is not relivant.
29480 * <script type="text/javascript">
29484 * @class Roo.MessageBox
29485 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29489 Roo.Msg.alert('Status', 'Changes saved successfully.');
29491 // Prompt for user data:
29492 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29494 // process text value...
29498 // Show a dialog using config options:
29500 title:'Save Changes?',
29501 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29502 buttons: Roo.Msg.YESNOCANCEL,
29509 Roo.MessageBox = function(){
29510 var dlg, opt, mask, waitTimer;
29511 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29512 var buttons, activeTextEl, bwidth;
29515 var handleButton = function(button){
29517 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29521 var handleHide = function(){
29522 if(opt && opt.cls){
29523 dlg.el.removeClass(opt.cls);
29526 Roo.TaskMgr.stop(waitTimer);
29532 var updateButtons = function(b){
29535 buttons["ok"].hide();
29536 buttons["cancel"].hide();
29537 buttons["yes"].hide();
29538 buttons["no"].hide();
29539 dlg.footer.dom.style.display = 'none';
29542 dlg.footer.dom.style.display = '';
29543 for(var k in buttons){
29544 if(typeof buttons[k] != "function"){
29547 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29548 width += buttons[k].el.getWidth()+15;
29558 var handleEsc = function(d, k, e){
29559 if(opt && opt.closable !== false){
29569 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29570 * @return {Roo.BasicDialog} The BasicDialog element
29572 getDialog : function(){
29574 dlg = new Roo.BasicDialog("x-msg-box", {
29579 constraintoviewport:false,
29581 collapsible : false,
29584 width:400, height:100,
29585 buttonAlign:"center",
29586 closeClick : function(){
29587 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29588 handleButton("no");
29590 handleButton("cancel");
29594 dlg.on("hide", handleHide);
29596 dlg.addKeyListener(27, handleEsc);
29598 var bt = this.buttonText;
29599 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29600 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29601 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29602 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29603 bodyEl = dlg.body.createChild({
29605 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>'
29607 msgEl = bodyEl.dom.firstChild;
29608 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29609 textboxEl.enableDisplayMode();
29610 textboxEl.addKeyListener([10,13], function(){
29611 if(dlg.isVisible() && opt && opt.buttons){
29612 if(opt.buttons.ok){
29613 handleButton("ok");
29614 }else if(opt.buttons.yes){
29615 handleButton("yes");
29619 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29620 textareaEl.enableDisplayMode();
29621 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29622 progressEl.enableDisplayMode();
29623 var pf = progressEl.dom.firstChild;
29625 pp = Roo.get(pf.firstChild);
29626 pp.setHeight(pf.offsetHeight);
29634 * Updates the message box body text
29635 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29636 * the XHTML-compliant non-breaking space character '&#160;')
29637 * @return {Roo.MessageBox} This message box
29639 updateText : function(text){
29640 if(!dlg.isVisible() && !opt.width){
29641 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29643 msgEl.innerHTML = text || ' ';
29644 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29645 Math.max(opt.minWidth || this.minWidth, bwidth));
29647 activeTextEl.setWidth(w);
29649 if(dlg.isVisible()){
29650 dlg.fixedcenter = false;
29652 dlg.setContentSize(w, bodyEl.getHeight());
29653 if(dlg.isVisible()){
29654 dlg.fixedcenter = true;
29660 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29661 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29662 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29663 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29664 * @return {Roo.MessageBox} This message box
29666 updateProgress : function(value, text){
29668 this.updateText(text);
29670 if (pp) { // weird bug on my firefox - for some reason this is not defined
29671 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29677 * Returns true if the message box is currently displayed
29678 * @return {Boolean} True if the message box is visible, else false
29680 isVisible : function(){
29681 return dlg && dlg.isVisible();
29685 * Hides the message box if it is displayed
29688 if(this.isVisible()){
29694 * Displays a new message box, or reinitializes an existing message box, based on the config options
29695 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29696 * The following config object properties are supported:
29698 Property Type Description
29699 ---------- --------------- ------------------------------------------------------------------------------------
29700 animEl String/Element An id or Element from which the message box should animate as it opens and
29701 closes (defaults to undefined)
29702 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29703 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29704 closable Boolean False to hide the top-right close button (defaults to true). Note that
29705 progress and wait dialogs will ignore this property and always hide the
29706 close button as they can only be closed programmatically.
29707 cls String A custom CSS class to apply to the message box element
29708 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29709 displayed (defaults to 75)
29710 fn Function A callback function to execute after closing the dialog. The arguments to the
29711 function will be btn (the name of the button that was clicked, if applicable,
29712 e.g. "ok"), and text (the value of the active text field, if applicable).
29713 Progress and wait dialogs will ignore this option since they do not respond to
29714 user actions and can only be closed programmatically, so any required function
29715 should be called by the same code after it closes the dialog.
29716 icon String A CSS class that provides a background image to be used as an icon for
29717 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29718 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29719 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29720 modal Boolean False to allow user interaction with the page while the message box is
29721 displayed (defaults to true)
29722 msg String A string that will replace the existing message box body text (defaults
29723 to the XHTML-compliant non-breaking space character ' ')
29724 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29725 progress Boolean True to display a progress bar (defaults to false)
29726 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29727 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29728 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29729 title String The title text
29730 value String The string value to set into the active textbox element if displayed
29731 wait Boolean True to display a progress bar (defaults to false)
29732 width Number The width of the dialog in pixels
29739 msg: 'Please enter your address:',
29741 buttons: Roo.MessageBox.OKCANCEL,
29744 animEl: 'addAddressBtn'
29747 * @param {Object} config Configuration options
29748 * @return {Roo.MessageBox} This message box
29750 show : function(options){
29751 if(this.isVisible()){
29754 var d = this.getDialog();
29756 d.setTitle(opt.title || " ");
29757 d.close.setDisplayed(opt.closable !== false);
29758 activeTextEl = textboxEl;
29759 opt.prompt = opt.prompt || (opt.multiline ? true : false);
29764 textareaEl.setHeight(typeof opt.multiline == "number" ?
29765 opt.multiline : this.defaultTextHeight);
29766 activeTextEl = textareaEl;
29775 progressEl.setDisplayed(opt.progress === true);
29776 this.updateProgress(0);
29777 activeTextEl.dom.value = opt.value || "";
29779 dlg.setDefaultButton(activeTextEl);
29781 var bs = opt.buttons;
29784 db = buttons["ok"];
29785 }else if(bs && bs.yes){
29786 db = buttons["yes"];
29788 dlg.setDefaultButton(db);
29790 bwidth = updateButtons(opt.buttons);
29791 this.updateText(opt.msg);
29793 d.el.addClass(opt.cls);
29795 d.proxyDrag = opt.proxyDrag === true;
29796 d.modal = opt.modal !== false;
29797 d.mask = opt.modal !== false ? mask : false;
29798 if(!d.isVisible()){
29799 // force it to the end of the z-index stack so it gets a cursor in FF
29800 document.body.appendChild(dlg.el.dom);
29801 d.animateTarget = null;
29802 d.show(options.animEl);
29808 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
29809 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
29810 * and closing the message box when the process is complete.
29811 * @param {String} title The title bar text
29812 * @param {String} msg The message box body text
29813 * @return {Roo.MessageBox} This message box
29815 progress : function(title, msg){
29822 minWidth: this.minProgressWidth,
29829 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
29830 * If a callback function is passed it will be called after the user clicks the button, and the
29831 * id of the button that was clicked will be passed as the only parameter to the callback
29832 * (could also be the top-right close button).
29833 * @param {String} title The title bar text
29834 * @param {String} msg The message box body text
29835 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29836 * @param {Object} scope (optional) The scope of the callback function
29837 * @return {Roo.MessageBox} This message box
29839 alert : function(title, msg, fn, scope){
29852 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
29853 * interaction while waiting for a long-running process to complete that does not have defined intervals.
29854 * You are responsible for closing the message box when the process is complete.
29855 * @param {String} msg The message box body text
29856 * @param {String} title (optional) The title bar text
29857 * @return {Roo.MessageBox} This message box
29859 wait : function(msg, title){
29870 waitTimer = Roo.TaskMgr.start({
29872 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
29880 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
29881 * If a callback function is passed it will be called after the user clicks either button, and the id of the
29882 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
29883 * @param {String} title The title bar text
29884 * @param {String} msg The message box body text
29885 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29886 * @param {Object} scope (optional) The scope of the callback function
29887 * @return {Roo.MessageBox} This message box
29889 confirm : function(title, msg, fn, scope){
29893 buttons: this.YESNO,
29902 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
29903 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
29904 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
29905 * (could also be the top-right close button) and the text that was entered will be passed as the two
29906 * parameters to the callback.
29907 * @param {String} title The title bar text
29908 * @param {String} msg The message box body text
29909 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29910 * @param {Object} scope (optional) The scope of the callback function
29911 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
29912 * property, or the height in pixels to create the textbox (defaults to false / single-line)
29913 * @return {Roo.MessageBox} This message box
29915 prompt : function(title, msg, fn, scope, multiline){
29919 buttons: this.OKCANCEL,
29924 multiline: multiline,
29931 * Button config that displays a single OK button
29936 * Button config that displays Yes and No buttons
29939 YESNO : {yes:true, no:true},
29941 * Button config that displays OK and Cancel buttons
29944 OKCANCEL : {ok:true, cancel:true},
29946 * Button config that displays Yes, No and Cancel buttons
29949 YESNOCANCEL : {yes:true, no:true, cancel:true},
29952 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
29955 defaultTextHeight : 75,
29957 * The maximum width in pixels of the message box (defaults to 600)
29962 * The minimum width in pixels of the message box (defaults to 100)
29967 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
29968 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
29971 minProgressWidth : 250,
29973 * An object containing the default button text strings that can be overriden for localized language support.
29974 * Supported properties are: ok, cancel, yes and no.
29975 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
29988 * Shorthand for {@link Roo.MessageBox}
29990 Roo.Msg = Roo.MessageBox;/*
29992 * Ext JS Library 1.1.1
29993 * Copyright(c) 2006-2007, Ext JS, LLC.
29995 * Originally Released Under LGPL - original licence link has changed is not relivant.
29998 * <script type="text/javascript">
30001 * @class Roo.QuickTips
30002 * Provides attractive and customizable tooltips for any element.
30005 Roo.QuickTips = function(){
30006 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30007 var ce, bd, xy, dd;
30008 var visible = false, disabled = true, inited = false;
30009 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30011 var onOver = function(e){
30015 var t = e.getTarget();
30016 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30019 if(ce && t == ce.el){
30020 clearTimeout(hideProc);
30023 if(t && tagEls[t.id]){
30024 tagEls[t.id].el = t;
30025 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30028 var ttp, et = Roo.fly(t);
30029 var ns = cfg.namespace;
30030 if(tm.interceptTitles && t.title){
30033 t.removeAttribute("title");
30034 e.preventDefault();
30036 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30039 showProc = show.defer(tm.showDelay, tm, [{
30042 width: et.getAttributeNS(ns, cfg.width),
30043 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30044 title: et.getAttributeNS(ns, cfg.title),
30045 cls: et.getAttributeNS(ns, cfg.cls)
30050 var onOut = function(e){
30051 clearTimeout(showProc);
30052 var t = e.getTarget();
30053 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30054 hideProc = setTimeout(hide, tm.hideDelay);
30058 var onMove = function(e){
30064 if(tm.trackMouse && ce){
30069 var onDown = function(e){
30070 clearTimeout(showProc);
30071 clearTimeout(hideProc);
30073 if(tm.hideOnClick){
30076 tm.enable.defer(100, tm);
30081 var getPad = function(){
30082 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30085 var show = function(o){
30089 clearTimeout(dismissProc);
30091 if(removeCls){ // in case manually hidden
30092 el.removeClass(removeCls);
30096 el.addClass(ce.cls);
30097 removeCls = ce.cls;
30100 tipTitle.update(ce.title);
30103 tipTitle.update('');
30106 el.dom.style.width = tm.maxWidth+'px';
30107 //tipBody.dom.style.width = '';
30108 tipBodyText.update(o.text);
30109 var p = getPad(), w = ce.width;
30111 var td = tipBodyText.dom;
30112 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30113 if(aw > tm.maxWidth){
30115 }else if(aw < tm.minWidth){
30121 //tipBody.setWidth(w);
30122 el.setWidth(parseInt(w, 10) + p);
30123 if(ce.autoHide === false){
30124 close.setDisplayed(true);
30129 close.setDisplayed(false);
30135 el.avoidY = xy[1]-18;
30140 el.setStyle("visibility", "visible");
30141 el.fadeIn({callback: afterShow});
30147 var afterShow = function(){
30151 if(tm.autoDismiss && ce.autoHide !== false){
30152 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30157 var hide = function(noanim){
30158 clearTimeout(dismissProc);
30159 clearTimeout(hideProc);
30161 if(el.isVisible()){
30163 if(noanim !== true && tm.animate){
30164 el.fadeOut({callback: afterHide});
30171 var afterHide = function(){
30174 el.removeClass(removeCls);
30181 * @cfg {Number} minWidth
30182 * The minimum width of the quick tip (defaults to 40)
30186 * @cfg {Number} maxWidth
30187 * The maximum width of the quick tip (defaults to 300)
30191 * @cfg {Boolean} interceptTitles
30192 * True to automatically use the element's DOM title value if available (defaults to false)
30194 interceptTitles : false,
30196 * @cfg {Boolean} trackMouse
30197 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30199 trackMouse : false,
30201 * @cfg {Boolean} hideOnClick
30202 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30204 hideOnClick : true,
30206 * @cfg {Number} showDelay
30207 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30211 * @cfg {Number} hideDelay
30212 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30216 * @cfg {Boolean} autoHide
30217 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30218 * Used in conjunction with hideDelay.
30223 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30224 * (defaults to true). Used in conjunction with autoDismissDelay.
30226 autoDismiss : true,
30229 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30231 autoDismissDelay : 5000,
30233 * @cfg {Boolean} animate
30234 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30239 * @cfg {String} title
30240 * Title text to display (defaults to ''). This can be any valid HTML markup.
30244 * @cfg {String} text
30245 * Body text to display (defaults to ''). This can be any valid HTML markup.
30249 * @cfg {String} cls
30250 * A CSS class to apply to the base quick tip element (defaults to '').
30254 * @cfg {Number} width
30255 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30256 * minWidth or maxWidth.
30261 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30262 * or display QuickTips in a page.
30265 tm = Roo.QuickTips;
30266 cfg = tm.tagConfig;
30268 if(!Roo.isReady){ // allow calling of init() before onReady
30269 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30272 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30273 el.fxDefaults = {stopFx: true};
30274 // maximum custom styling
30275 //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>');
30276 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>');
30277 tipTitle = el.child('h3');
30278 tipTitle.enableDisplayMode("block");
30279 tipBody = el.child('div.x-tip-bd');
30280 tipBodyText = el.child('div.x-tip-bd-inner');
30281 //bdLeft = el.child('div.x-tip-bd-left');
30282 //bdRight = el.child('div.x-tip-bd-right');
30283 close = el.child('div.x-tip-close');
30284 close.enableDisplayMode("block");
30285 close.on("click", hide);
30286 var d = Roo.get(document);
30287 d.on("mousedown", onDown);
30288 d.on("mouseover", onOver);
30289 d.on("mouseout", onOut);
30290 d.on("mousemove", onMove);
30291 esc = d.addKeyListener(27, hide);
30294 dd = el.initDD("default", null, {
30295 onDrag : function(){
30299 dd.setHandleElId(tipTitle.id);
30308 * Configures a new quick tip instance and assigns it to a target element. The following config options
30311 Property Type Description
30312 ---------- --------------------- ------------------------------------------------------------------------
30313 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30315 * @param {Object} config The config object
30317 register : function(config){
30318 var cs = config instanceof Array ? config : arguments;
30319 for(var i = 0, len = cs.length; i < len; i++) {
30321 var target = c.target;
30323 if(target instanceof Array){
30324 for(var j = 0, jlen = target.length; j < jlen; j++){
30325 tagEls[target[j]] = c;
30328 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30335 * Removes this quick tip from its element and destroys it.
30336 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30338 unregister : function(el){
30339 delete tagEls[Roo.id(el)];
30343 * Enable this quick tip.
30345 enable : function(){
30346 if(inited && disabled){
30348 if(locks.length < 1){
30355 * Disable this quick tip.
30357 disable : function(){
30359 clearTimeout(showProc);
30360 clearTimeout(hideProc);
30361 clearTimeout(dismissProc);
30369 * Returns true if the quick tip is enabled, else false.
30371 isEnabled : function(){
30378 attribute : "qtip",
30388 // backwards compat
30389 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30391 * Ext JS Library 1.1.1
30392 * Copyright(c) 2006-2007, Ext JS, LLC.
30394 * Originally Released Under LGPL - original licence link has changed is not relivant.
30397 * <script type="text/javascript">
30402 * @class Roo.tree.TreePanel
30403 * @extends Roo.data.Tree
30405 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30406 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30407 * @cfg {Boolean} enableDD true to enable drag and drop
30408 * @cfg {Boolean} enableDrag true to enable just drag
30409 * @cfg {Boolean} enableDrop true to enable just drop
30410 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30411 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30412 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30413 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30414 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30415 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30416 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30417 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30418 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30419 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30420 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30421 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30422 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30423 * @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>
30424 * @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>
30427 * @param {String/HTMLElement/Element} el The container element
30428 * @param {Object} config
30430 Roo.tree.TreePanel = function(el, config){
30432 var loader = false;
30434 root = config.root;
30435 delete config.root;
30437 if (config.loader) {
30438 loader = config.loader;
30439 delete config.loader;
30442 Roo.apply(this, config);
30443 Roo.tree.TreePanel.superclass.constructor.call(this);
30444 this.el = Roo.get(el);
30445 this.el.addClass('x-tree');
30446 //console.log(root);
30448 this.setRootNode( Roo.factory(root, Roo.tree));
30451 this.loader = Roo.factory(loader, Roo.tree);
30454 * Read-only. The id of the container element becomes this TreePanel's id.
30456 this.id = this.el.id;
30459 * @event beforeload
30460 * Fires before a node is loaded, return false to cancel
30461 * @param {Node} node The node being loaded
30463 "beforeload" : true,
30466 * Fires when a node is loaded
30467 * @param {Node} node The node that was loaded
30471 * @event textchange
30472 * Fires when the text for a node is changed
30473 * @param {Node} node The node
30474 * @param {String} text The new text
30475 * @param {String} oldText The old text
30477 "textchange" : true,
30479 * @event beforeexpand
30480 * Fires before a node is expanded, return false to cancel.
30481 * @param {Node} node The node
30482 * @param {Boolean} deep
30483 * @param {Boolean} anim
30485 "beforeexpand" : true,
30487 * @event beforecollapse
30488 * Fires before a node is collapsed, return false to cancel.
30489 * @param {Node} node The node
30490 * @param {Boolean} deep
30491 * @param {Boolean} anim
30493 "beforecollapse" : true,
30496 * Fires when a node is expanded
30497 * @param {Node} node The node
30501 * @event disabledchange
30502 * Fires when the disabled status of a node changes
30503 * @param {Node} node The node
30504 * @param {Boolean} disabled
30506 "disabledchange" : true,
30509 * Fires when a node is collapsed
30510 * @param {Node} node The node
30514 * @event beforeclick
30515 * Fires before click processing on a node. Return false to cancel the default action.
30516 * @param {Node} node The node
30517 * @param {Roo.EventObject} e The event object
30519 "beforeclick":true,
30521 * @event checkchange
30522 * Fires when a node with a checkbox's checked property changes
30523 * @param {Node} this This node
30524 * @param {Boolean} checked
30526 "checkchange":true,
30529 * Fires when a node is clicked
30530 * @param {Node} node The node
30531 * @param {Roo.EventObject} e The event object
30536 * Fires when a node is double clicked
30537 * @param {Node} node The node
30538 * @param {Roo.EventObject} e The event object
30542 * @event contextmenu
30543 * Fires when a node is right clicked
30544 * @param {Node} node The node
30545 * @param {Roo.EventObject} e The event object
30547 "contextmenu":true,
30549 * @event beforechildrenrendered
30550 * Fires right before the child nodes for a node are rendered
30551 * @param {Node} node The node
30553 "beforechildrenrendered":true,
30556 * Fires when a node starts being dragged
30557 * @param {Roo.tree.TreePanel} this
30558 * @param {Roo.tree.TreeNode} node
30559 * @param {event} e The raw browser event
30561 "startdrag" : true,
30564 * Fires when a drag operation is complete
30565 * @param {Roo.tree.TreePanel} this
30566 * @param {Roo.tree.TreeNode} node
30567 * @param {event} e The raw browser event
30572 * Fires when a dragged node is dropped on a valid DD target
30573 * @param {Roo.tree.TreePanel} this
30574 * @param {Roo.tree.TreeNode} node
30575 * @param {DD} dd The dd it was dropped on
30576 * @param {event} e The raw browser event
30580 * @event beforenodedrop
30581 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30582 * passed to handlers has the following properties:<br />
30583 * <ul style="padding:5px;padding-left:16px;">
30584 * <li>tree - The TreePanel</li>
30585 * <li>target - The node being targeted for the drop</li>
30586 * <li>data - The drag data from the drag source</li>
30587 * <li>point - The point of the drop - append, above or below</li>
30588 * <li>source - The drag source</li>
30589 * <li>rawEvent - Raw mouse event</li>
30590 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30591 * to be inserted by setting them on this object.</li>
30592 * <li>cancel - Set this to true to cancel the drop.</li>
30594 * @param {Object} dropEvent
30596 "beforenodedrop" : true,
30599 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30600 * passed to handlers has the following properties:<br />
30601 * <ul style="padding:5px;padding-left:16px;">
30602 * <li>tree - The TreePanel</li>
30603 * <li>target - The node being targeted for the drop</li>
30604 * <li>data - The drag data from the drag source</li>
30605 * <li>point - The point of the drop - append, above or below</li>
30606 * <li>source - The drag source</li>
30607 * <li>rawEvent - Raw mouse event</li>
30608 * <li>dropNode - Dropped node(s).</li>
30610 * @param {Object} dropEvent
30614 * @event nodedragover
30615 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30616 * passed to handlers has the following properties:<br />
30617 * <ul style="padding:5px;padding-left:16px;">
30618 * <li>tree - The TreePanel</li>
30619 * <li>target - The node being targeted for the drop</li>
30620 * <li>data - The drag data from the drag source</li>
30621 * <li>point - The point of the drop - append, above or below</li>
30622 * <li>source - The drag source</li>
30623 * <li>rawEvent - Raw mouse event</li>
30624 * <li>dropNode - Drop node(s) provided by the source.</li>
30625 * <li>cancel - Set this to true to signal drop not allowed.</li>
30627 * @param {Object} dragOverEvent
30629 "nodedragover" : true
30632 if(this.singleExpand){
30633 this.on("beforeexpand", this.restrictExpand, this);
30636 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30637 rootVisible : true,
30638 animate: Roo.enableFx,
30641 hlDrop : Roo.enableFx,
30645 rendererTip: false,
30647 restrictExpand : function(node){
30648 var p = node.parentNode;
30650 if(p.expandedChild && p.expandedChild.parentNode == p){
30651 p.expandedChild.collapse();
30653 p.expandedChild = node;
30657 // private override
30658 setRootNode : function(node){
30659 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30660 if(!this.rootVisible){
30661 node.ui = new Roo.tree.RootTreeNodeUI(node);
30667 * Returns the container element for this TreePanel
30669 getEl : function(){
30674 * Returns the default TreeLoader for this TreePanel
30676 getLoader : function(){
30677 return this.loader;
30683 expandAll : function(){
30684 this.root.expand(true);
30688 * Collapse all nodes
30690 collapseAll : function(){
30691 this.root.collapse(true);
30695 * Returns the selection model used by this TreePanel
30697 getSelectionModel : function(){
30698 if(!this.selModel){
30699 this.selModel = new Roo.tree.DefaultSelectionModel();
30701 return this.selModel;
30705 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30706 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30707 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30710 getChecked : function(a, startNode){
30711 startNode = startNode || this.root;
30713 var f = function(){
30714 if(this.attributes.checked){
30715 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30718 startNode.cascade(f);
30723 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30724 * @param {String} path
30725 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30726 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30727 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30729 expandPath : function(path, attr, callback){
30730 attr = attr || "id";
30731 var keys = path.split(this.pathSeparator);
30732 var curNode = this.root;
30733 if(curNode.attributes[attr] != keys[1]){ // invalid root
30735 callback(false, null);
30740 var f = function(){
30741 if(++index == keys.length){
30743 callback(true, curNode);
30747 var c = curNode.findChild(attr, keys[index]);
30750 callback(false, curNode);
30755 c.expand(false, false, f);
30757 curNode.expand(false, false, f);
30761 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30762 * @param {String} path
30763 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30764 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
30765 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
30767 selectPath : function(path, attr, callback){
30768 attr = attr || "id";
30769 var keys = path.split(this.pathSeparator);
30770 var v = keys.pop();
30771 if(keys.length > 0){
30772 var f = function(success, node){
30773 if(success && node){
30774 var n = node.findChild(attr, v);
30780 }else if(callback){
30781 callback(false, n);
30785 callback(false, n);
30789 this.expandPath(keys.join(this.pathSeparator), attr, f);
30791 this.root.select();
30793 callback(true, this.root);
30798 getTreeEl : function(){
30803 * Trigger rendering of this TreePanel
30805 render : function(){
30806 if (this.innerCt) {
30807 return this; // stop it rendering more than once!!
30810 this.innerCt = this.el.createChild({tag:"ul",
30811 cls:"x-tree-root-ct " +
30812 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
30814 if(this.containerScroll){
30815 Roo.dd.ScrollManager.register(this.el);
30817 if((this.enableDD || this.enableDrop) && !this.dropZone){
30819 * The dropZone used by this tree if drop is enabled
30820 * @type Roo.tree.TreeDropZone
30822 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
30823 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
30826 if((this.enableDD || this.enableDrag) && !this.dragZone){
30828 * The dragZone used by this tree if drag is enabled
30829 * @type Roo.tree.TreeDragZone
30831 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
30832 ddGroup: this.ddGroup || "TreeDD",
30833 scroll: this.ddScroll
30836 this.getSelectionModel().init(this);
30838 console.log("ROOT not set in tree");
30841 this.root.render();
30842 if(!this.rootVisible){
30843 this.root.renderChildren();
30849 * Ext JS Library 1.1.1
30850 * Copyright(c) 2006-2007, Ext JS, LLC.
30852 * Originally Released Under LGPL - original licence link has changed is not relivant.
30855 * <script type="text/javascript">
30860 * @class Roo.tree.DefaultSelectionModel
30861 * @extends Roo.util.Observable
30862 * The default single selection for a TreePanel.
30864 Roo.tree.DefaultSelectionModel = function(){
30865 this.selNode = null;
30869 * @event selectionchange
30870 * Fires when the selected node changes
30871 * @param {DefaultSelectionModel} this
30872 * @param {TreeNode} node the new selection
30874 "selectionchange" : true,
30877 * @event beforeselect
30878 * Fires before the selected node changes, return false to cancel the change
30879 * @param {DefaultSelectionModel} this
30880 * @param {TreeNode} node the new selection
30881 * @param {TreeNode} node the old selection
30883 "beforeselect" : true
30887 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
30888 init : function(tree){
30890 tree.getTreeEl().on("keydown", this.onKeyDown, this);
30891 tree.on("click", this.onNodeClick, this);
30894 onNodeClick : function(node, e){
30895 if (e.ctrlKey && this.selNode == node) {
30896 this.unselect(node);
30904 * @param {TreeNode} node The node to select
30905 * @return {TreeNode} The selected node
30907 select : function(node){
30908 var last = this.selNode;
30909 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
30911 last.ui.onSelectedChange(false);
30913 this.selNode = node;
30914 node.ui.onSelectedChange(true);
30915 this.fireEvent("selectionchange", this, node, last);
30922 * @param {TreeNode} node The node to unselect
30924 unselect : function(node){
30925 if(this.selNode == node){
30926 this.clearSelections();
30931 * Clear all selections
30933 clearSelections : function(){
30934 var n = this.selNode;
30936 n.ui.onSelectedChange(false);
30937 this.selNode = null;
30938 this.fireEvent("selectionchange", this, null);
30944 * Get the selected node
30945 * @return {TreeNode} The selected node
30947 getSelectedNode : function(){
30948 return this.selNode;
30952 * Returns true if the node is selected
30953 * @param {TreeNode} node The node to check
30954 * @return {Boolean}
30956 isSelected : function(node){
30957 return this.selNode == node;
30961 * Selects the node above the selected node in the tree, intelligently walking the nodes
30962 * @return TreeNode The new selection
30964 selectPrevious : function(){
30965 var s = this.selNode || this.lastSelNode;
30969 var ps = s.previousSibling;
30971 if(!ps.isExpanded() || ps.childNodes.length < 1){
30972 return this.select(ps);
30974 var lc = ps.lastChild;
30975 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
30978 return this.select(lc);
30980 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
30981 return this.select(s.parentNode);
30987 * Selects the node above the selected node in the tree, intelligently walking the nodes
30988 * @return TreeNode The new selection
30990 selectNext : function(){
30991 var s = this.selNode || this.lastSelNode;
30995 if(s.firstChild && s.isExpanded()){
30996 return this.select(s.firstChild);
30997 }else if(s.nextSibling){
30998 return this.select(s.nextSibling);
30999 }else if(s.parentNode){
31001 s.parentNode.bubble(function(){
31002 if(this.nextSibling){
31003 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31012 onKeyDown : function(e){
31013 var s = this.selNode || this.lastSelNode;
31014 // undesirable, but required
31019 var k = e.getKey();
31027 this.selectPrevious();
31030 e.preventDefault();
31031 if(s.hasChildNodes()){
31032 if(!s.isExpanded()){
31034 }else if(s.firstChild){
31035 this.select(s.firstChild, e);
31040 e.preventDefault();
31041 if(s.hasChildNodes() && s.isExpanded()){
31043 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31044 this.select(s.parentNode, e);
31052 * @class Roo.tree.MultiSelectionModel
31053 * @extends Roo.util.Observable
31054 * Multi selection for a TreePanel.
31056 Roo.tree.MultiSelectionModel = function(){
31057 this.selNodes = [];
31061 * @event selectionchange
31062 * Fires when the selected nodes change
31063 * @param {MultiSelectionModel} this
31064 * @param {Array} nodes Array of the selected nodes
31066 "selectionchange" : true
31070 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31071 init : function(tree){
31073 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31074 tree.on("click", this.onNodeClick, this);
31077 onNodeClick : function(node, e){
31078 this.select(node, e, e.ctrlKey);
31083 * @param {TreeNode} node The node to select
31084 * @param {EventObject} e (optional) An event associated with the selection
31085 * @param {Boolean} keepExisting True to retain existing selections
31086 * @return {TreeNode} The selected node
31088 select : function(node, e, keepExisting){
31089 if(keepExisting !== true){
31090 this.clearSelections(true);
31092 if(this.isSelected(node)){
31093 this.lastSelNode = node;
31096 this.selNodes.push(node);
31097 this.selMap[node.id] = node;
31098 this.lastSelNode = node;
31099 node.ui.onSelectedChange(true);
31100 this.fireEvent("selectionchange", this, this.selNodes);
31106 * @param {TreeNode} node The node to unselect
31108 unselect : function(node){
31109 if(this.selMap[node.id]){
31110 node.ui.onSelectedChange(false);
31111 var sn = this.selNodes;
31114 index = sn.indexOf(node);
31116 for(var i = 0, len = sn.length; i < len; i++){
31124 this.selNodes.splice(index, 1);
31126 delete this.selMap[node.id];
31127 this.fireEvent("selectionchange", this, this.selNodes);
31132 * Clear all selections
31134 clearSelections : function(suppressEvent){
31135 var sn = this.selNodes;
31137 for(var i = 0, len = sn.length; i < len; i++){
31138 sn[i].ui.onSelectedChange(false);
31140 this.selNodes = [];
31142 if(suppressEvent !== true){
31143 this.fireEvent("selectionchange", this, this.selNodes);
31149 * Returns true if the node is selected
31150 * @param {TreeNode} node The node to check
31151 * @return {Boolean}
31153 isSelected : function(node){
31154 return this.selMap[node.id] ? true : false;
31158 * Returns an array of the selected nodes
31161 getSelectedNodes : function(){
31162 return this.selNodes;
31165 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31167 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31169 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31172 * Ext JS Library 1.1.1
31173 * Copyright(c) 2006-2007, Ext JS, LLC.
31175 * Originally Released Under LGPL - original licence link has changed is not relivant.
31178 * <script type="text/javascript">
31182 * @class Roo.tree.TreeNode
31183 * @extends Roo.data.Node
31184 * @cfg {String} text The text for this node
31185 * @cfg {Boolean} expanded true to start the node expanded
31186 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31187 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31188 * @cfg {Boolean} disabled true to start the node disabled
31189 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31190 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31191 * @cfg {String} cls A css class to be added to the node
31192 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31193 * @cfg {String} href URL of the link used for the node (defaults to #)
31194 * @cfg {String} hrefTarget target frame for the link
31195 * @cfg {String} qtip An Ext QuickTip for the node
31196 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31197 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31198 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31199 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31200 * (defaults to undefined with no checkbox rendered)
31202 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31204 Roo.tree.TreeNode = function(attributes){
31205 attributes = attributes || {};
31206 if(typeof attributes == "string"){
31207 attributes = {text: attributes};
31209 this.childrenRendered = false;
31210 this.rendered = false;
31211 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31212 this.expanded = attributes.expanded === true;
31213 this.isTarget = attributes.isTarget !== false;
31214 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31215 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31218 * Read-only. The text for this node. To change it use setText().
31221 this.text = attributes.text;
31223 * True if this node is disabled.
31226 this.disabled = attributes.disabled === true;
31230 * @event textchange
31231 * Fires when the text for this node is changed
31232 * @param {Node} this This node
31233 * @param {String} text The new text
31234 * @param {String} oldText The old text
31236 "textchange" : true,
31238 * @event beforeexpand
31239 * Fires before this node is expanded, return false to cancel.
31240 * @param {Node} this This node
31241 * @param {Boolean} deep
31242 * @param {Boolean} anim
31244 "beforeexpand" : true,
31246 * @event beforecollapse
31247 * Fires before this node is collapsed, return false to cancel.
31248 * @param {Node} this This node
31249 * @param {Boolean} deep
31250 * @param {Boolean} anim
31252 "beforecollapse" : true,
31255 * Fires when this node is expanded
31256 * @param {Node} this This node
31260 * @event disabledchange
31261 * Fires when the disabled status of this node changes
31262 * @param {Node} this This node
31263 * @param {Boolean} disabled
31265 "disabledchange" : true,
31268 * Fires when this node is collapsed
31269 * @param {Node} this This node
31273 * @event beforeclick
31274 * Fires before click processing. Return false to cancel the default action.
31275 * @param {Node} this This node
31276 * @param {Roo.EventObject} e The event object
31278 "beforeclick":true,
31280 * @event checkchange
31281 * Fires when a node with a checkbox's checked property changes
31282 * @param {Node} this This node
31283 * @param {Boolean} checked
31285 "checkchange":true,
31288 * Fires when this node is clicked
31289 * @param {Node} this This node
31290 * @param {Roo.EventObject} e The event object
31295 * Fires when this node is double clicked
31296 * @param {Node} this This node
31297 * @param {Roo.EventObject} e The event object
31301 * @event contextmenu
31302 * Fires when this node is right clicked
31303 * @param {Node} this This node
31304 * @param {Roo.EventObject} e The event object
31306 "contextmenu":true,
31308 * @event beforechildrenrendered
31309 * Fires right before the child nodes for this node are rendered
31310 * @param {Node} this This node
31312 "beforechildrenrendered":true
31315 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31318 * Read-only. The UI for this node
31321 this.ui = new uiClass(this);
31323 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31324 preventHScroll: true,
31326 * Returns true if this node is expanded
31327 * @return {Boolean}
31329 isExpanded : function(){
31330 return this.expanded;
31334 * Returns the UI object for this node
31335 * @return {TreeNodeUI}
31337 getUI : function(){
31341 // private override
31342 setFirstChild : function(node){
31343 var of = this.firstChild;
31344 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31345 if(this.childrenRendered && of && node != of){
31346 of.renderIndent(true, true);
31349 this.renderIndent(true, true);
31353 // private override
31354 setLastChild : function(node){
31355 var ol = this.lastChild;
31356 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31357 if(this.childrenRendered && ol && node != ol){
31358 ol.renderIndent(true, true);
31361 this.renderIndent(true, true);
31365 // these methods are overridden to provide lazy rendering support
31366 // private override
31367 appendChild : function(){
31368 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31369 if(node && this.childrenRendered){
31372 this.ui.updateExpandIcon();
31376 // private override
31377 removeChild : function(node){
31378 this.ownerTree.getSelectionModel().unselect(node);
31379 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31380 // if it's been rendered remove dom node
31381 if(this.childrenRendered){
31384 if(this.childNodes.length < 1){
31385 this.collapse(false, false);
31387 this.ui.updateExpandIcon();
31389 if(!this.firstChild) {
31390 this.childrenRendered = false;
31395 // private override
31396 insertBefore : function(node, refNode){
31397 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31398 if(newNode && refNode && this.childrenRendered){
31401 this.ui.updateExpandIcon();
31406 * Sets the text for this node
31407 * @param {String} text
31409 setText : function(text){
31410 var oldText = this.text;
31412 this.attributes.text = text;
31413 if(this.rendered){ // event without subscribing
31414 this.ui.onTextChange(this, text, oldText);
31416 this.fireEvent("textchange", this, text, oldText);
31420 * Triggers selection of this node
31422 select : function(){
31423 this.getOwnerTree().getSelectionModel().select(this);
31427 * Triggers deselection of this node
31429 unselect : function(){
31430 this.getOwnerTree().getSelectionModel().unselect(this);
31434 * Returns true if this node is selected
31435 * @return {Boolean}
31437 isSelected : function(){
31438 return this.getOwnerTree().getSelectionModel().isSelected(this);
31442 * Expand this node.
31443 * @param {Boolean} deep (optional) True to expand all children as well
31444 * @param {Boolean} anim (optional) false to cancel the default animation
31445 * @param {Function} callback (optional) A callback to be called when
31446 * expanding this node completes (does not wait for deep expand to complete).
31447 * Called with 1 parameter, this node.
31449 expand : function(deep, anim, callback){
31450 if(!this.expanded){
31451 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31454 if(!this.childrenRendered){
31455 this.renderChildren();
31457 this.expanded = true;
31458 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31459 this.ui.animExpand(function(){
31460 this.fireEvent("expand", this);
31461 if(typeof callback == "function"){
31465 this.expandChildNodes(true);
31467 }.createDelegate(this));
31471 this.fireEvent("expand", this);
31472 if(typeof callback == "function"){
31477 if(typeof callback == "function"){
31482 this.expandChildNodes(true);
31486 isHiddenRoot : function(){
31487 return this.isRoot && !this.getOwnerTree().rootVisible;
31491 * Collapse this node.
31492 * @param {Boolean} deep (optional) True to collapse all children as well
31493 * @param {Boolean} anim (optional) false to cancel the default animation
31495 collapse : function(deep, anim){
31496 if(this.expanded && !this.isHiddenRoot()){
31497 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31500 this.expanded = false;
31501 if((this.getOwnerTree().animate && anim !== false) || anim){
31502 this.ui.animCollapse(function(){
31503 this.fireEvent("collapse", this);
31505 this.collapseChildNodes(true);
31507 }.createDelegate(this));
31510 this.ui.collapse();
31511 this.fireEvent("collapse", this);
31515 var cs = this.childNodes;
31516 for(var i = 0, len = cs.length; i < len; i++) {
31517 cs[i].collapse(true, false);
31523 delayedExpand : function(delay){
31524 if(!this.expandProcId){
31525 this.expandProcId = this.expand.defer(delay, this);
31530 cancelExpand : function(){
31531 if(this.expandProcId){
31532 clearTimeout(this.expandProcId);
31534 this.expandProcId = false;
31538 * Toggles expanded/collapsed state of the node
31540 toggle : function(){
31549 * Ensures all parent nodes are expanded
31551 ensureVisible : function(callback){
31552 var tree = this.getOwnerTree();
31553 tree.expandPath(this.parentNode.getPath(), false, function(){
31554 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31555 Roo.callback(callback);
31556 }.createDelegate(this));
31560 * Expand all child nodes
31561 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31563 expandChildNodes : function(deep){
31564 var cs = this.childNodes;
31565 for(var i = 0, len = cs.length; i < len; i++) {
31566 cs[i].expand(deep);
31571 * Collapse all child nodes
31572 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31574 collapseChildNodes : function(deep){
31575 var cs = this.childNodes;
31576 for(var i = 0, len = cs.length; i < len; i++) {
31577 cs[i].collapse(deep);
31582 * Disables this node
31584 disable : function(){
31585 this.disabled = true;
31587 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31588 this.ui.onDisableChange(this, true);
31590 this.fireEvent("disabledchange", this, true);
31594 * Enables this node
31596 enable : function(){
31597 this.disabled = false;
31598 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31599 this.ui.onDisableChange(this, false);
31601 this.fireEvent("disabledchange", this, false);
31605 renderChildren : function(suppressEvent){
31606 if(suppressEvent !== false){
31607 this.fireEvent("beforechildrenrendered", this);
31609 var cs = this.childNodes;
31610 for(var i = 0, len = cs.length; i < len; i++){
31611 cs[i].render(true);
31613 this.childrenRendered = true;
31617 sort : function(fn, scope){
31618 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31619 if(this.childrenRendered){
31620 var cs = this.childNodes;
31621 for(var i = 0, len = cs.length; i < len; i++){
31622 cs[i].render(true);
31628 render : function(bulkRender){
31629 this.ui.render(bulkRender);
31630 if(!this.rendered){
31631 this.rendered = true;
31633 this.expanded = false;
31634 this.expand(false, false);
31640 renderIndent : function(deep, refresh){
31642 this.ui.childIndent = null;
31644 this.ui.renderIndent();
31645 if(deep === true && this.childrenRendered){
31646 var cs = this.childNodes;
31647 for(var i = 0, len = cs.length; i < len; i++){
31648 cs[i].renderIndent(true, refresh);
31654 * Ext JS Library 1.1.1
31655 * Copyright(c) 2006-2007, Ext JS, LLC.
31657 * Originally Released Under LGPL - original licence link has changed is not relivant.
31660 * <script type="text/javascript">
31664 * @class Roo.tree.AsyncTreeNode
31665 * @extends Roo.tree.TreeNode
31666 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31668 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31670 Roo.tree.AsyncTreeNode = function(config){
31671 this.loaded = false;
31672 this.loading = false;
31673 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31675 * @event beforeload
31676 * Fires before this node is loaded, return false to cancel
31677 * @param {Node} this This node
31679 this.addEvents({'beforeload':true, 'load': true});
31682 * Fires when this node is loaded
31683 * @param {Node} this This node
31686 * The loader used by this node (defaults to using the tree's defined loader)
31691 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31692 expand : function(deep, anim, callback){
31693 if(this.loading){ // if an async load is already running, waiting til it's done
31695 var f = function(){
31696 if(!this.loading){ // done loading
31697 clearInterval(timer);
31698 this.expand(deep, anim, callback);
31700 }.createDelegate(this);
31701 timer = setInterval(f, 200);
31705 if(this.fireEvent("beforeload", this) === false){
31708 this.loading = true;
31709 this.ui.beforeLoad(this);
31710 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31712 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31716 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31720 * Returns true if this node is currently loading
31721 * @return {Boolean}
31723 isLoading : function(){
31724 return this.loading;
31727 loadComplete : function(deep, anim, callback){
31728 this.loading = false;
31729 this.loaded = true;
31730 this.ui.afterLoad(this);
31731 this.fireEvent("load", this);
31732 this.expand(deep, anim, callback);
31736 * Returns true if this node has been loaded
31737 * @return {Boolean}
31739 isLoaded : function(){
31740 return this.loaded;
31743 hasChildNodes : function(){
31744 if(!this.isLeaf() && !this.loaded){
31747 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
31752 * Trigger a reload for this node
31753 * @param {Function} callback
31755 reload : function(callback){
31756 this.collapse(false, false);
31757 while(this.firstChild){
31758 this.removeChild(this.firstChild);
31760 this.childrenRendered = false;
31761 this.loaded = false;
31762 if(this.isHiddenRoot()){
31763 this.expanded = false;
31765 this.expand(false, false, callback);
31769 * Ext JS Library 1.1.1
31770 * Copyright(c) 2006-2007, Ext JS, LLC.
31772 * Originally Released Under LGPL - original licence link has changed is not relivant.
31775 * <script type="text/javascript">
31779 * @class Roo.tree.TreeNodeUI
31781 * @param {Object} node The node to render
31782 * The TreeNode UI implementation is separate from the
31783 * tree implementation. Unless you are customizing the tree UI,
31784 * you should never have to use this directly.
31786 Roo.tree.TreeNodeUI = function(node){
31788 this.rendered = false;
31789 this.animating = false;
31790 this.emptyIcon = Roo.BLANK_IMAGE_URL;
31793 Roo.tree.TreeNodeUI.prototype = {
31794 removeChild : function(node){
31796 this.ctNode.removeChild(node.ui.getEl());
31800 beforeLoad : function(){
31801 this.addClass("x-tree-node-loading");
31804 afterLoad : function(){
31805 this.removeClass("x-tree-node-loading");
31808 onTextChange : function(node, text, oldText){
31810 this.textNode.innerHTML = text;
31814 onDisableChange : function(node, state){
31815 this.disabled = state;
31817 this.addClass("x-tree-node-disabled");
31819 this.removeClass("x-tree-node-disabled");
31823 onSelectedChange : function(state){
31826 this.addClass("x-tree-selected");
31829 this.removeClass("x-tree-selected");
31833 onMove : function(tree, node, oldParent, newParent, index, refNode){
31834 this.childIndent = null;
31836 var targetNode = newParent.ui.getContainer();
31837 if(!targetNode){//target not rendered
31838 this.holder = document.createElement("div");
31839 this.holder.appendChild(this.wrap);
31842 var insertBefore = refNode ? refNode.ui.getEl() : null;
31844 targetNode.insertBefore(this.wrap, insertBefore);
31846 targetNode.appendChild(this.wrap);
31848 this.node.renderIndent(true);
31852 addClass : function(cls){
31854 Roo.fly(this.elNode).addClass(cls);
31858 removeClass : function(cls){
31860 Roo.fly(this.elNode).removeClass(cls);
31864 remove : function(){
31866 this.holder = document.createElement("div");
31867 this.holder.appendChild(this.wrap);
31871 fireEvent : function(){
31872 return this.node.fireEvent.apply(this.node, arguments);
31875 initEvents : function(){
31876 this.node.on("move", this.onMove, this);
31877 var E = Roo.EventManager;
31878 var a = this.anchor;
31880 var el = Roo.fly(a, '_treeui');
31882 if(Roo.isOpera){ // opera render bug ignores the CSS
31883 el.setStyle("text-decoration", "none");
31886 el.on("click", this.onClick, this);
31887 el.on("dblclick", this.onDblClick, this);
31890 Roo.EventManager.on(this.checkbox,
31891 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
31894 el.on("contextmenu", this.onContextMenu, this);
31896 var icon = Roo.fly(this.iconNode);
31897 icon.on("click", this.onClick, this);
31898 icon.on("dblclick", this.onDblClick, this);
31899 icon.on("contextmenu", this.onContextMenu, this);
31900 E.on(this.ecNode, "click", this.ecClick, this, true);
31902 if(this.node.disabled){
31903 this.addClass("x-tree-node-disabled");
31905 if(this.node.hidden){
31906 this.addClass("x-tree-node-disabled");
31908 var ot = this.node.getOwnerTree();
31909 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
31910 if(dd && (!this.node.isRoot || ot.rootVisible)){
31911 Roo.dd.Registry.register(this.elNode, {
31913 handles: this.getDDHandles(),
31919 getDDHandles : function(){
31920 return [this.iconNode, this.textNode];
31925 this.wrap.style.display = "none";
31931 this.wrap.style.display = "";
31935 onContextMenu : function(e){
31936 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
31937 e.preventDefault();
31939 this.fireEvent("contextmenu", this.node, e);
31943 onClick : function(e){
31948 if(this.fireEvent("beforeclick", this.node, e) !== false){
31949 if(!this.disabled && this.node.attributes.href){
31950 this.fireEvent("click", this.node, e);
31953 e.preventDefault();
31958 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
31959 this.node.toggle();
31962 this.fireEvent("click", this.node, e);
31968 onDblClick : function(e){
31969 e.preventDefault();
31974 this.toggleCheck();
31976 if(!this.animating && this.node.hasChildNodes()){
31977 this.node.toggle();
31979 this.fireEvent("dblclick", this.node, e);
31982 onCheckChange : function(){
31983 var checked = this.checkbox.checked;
31984 this.node.attributes.checked = checked;
31985 this.fireEvent('checkchange', this.node, checked);
31988 ecClick : function(e){
31989 if(!this.animating && this.node.hasChildNodes()){
31990 this.node.toggle();
31994 startDrop : function(){
31995 this.dropping = true;
31998 // delayed drop so the click event doesn't get fired on a drop
31999 endDrop : function(){
32000 setTimeout(function(){
32001 this.dropping = false;
32002 }.createDelegate(this), 50);
32005 expand : function(){
32006 this.updateExpandIcon();
32007 this.ctNode.style.display = "";
32010 focus : function(){
32011 if(!this.node.preventHScroll){
32012 try{this.anchor.focus();
32014 }else if(!Roo.isIE){
32016 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32017 var l = noscroll.scrollLeft;
32018 this.anchor.focus();
32019 noscroll.scrollLeft = l;
32024 toggleCheck : function(value){
32025 var cb = this.checkbox;
32027 cb.checked = (value === undefined ? !cb.checked : value);
32033 this.anchor.blur();
32037 animExpand : function(callback){
32038 var ct = Roo.get(this.ctNode);
32040 if(!this.node.hasChildNodes()){
32041 this.updateExpandIcon();
32042 this.ctNode.style.display = "";
32043 Roo.callback(callback);
32046 this.animating = true;
32047 this.updateExpandIcon();
32050 callback : function(){
32051 this.animating = false;
32052 Roo.callback(callback);
32055 duration: this.node.ownerTree.duration || .25
32059 highlight : function(){
32060 var tree = this.node.getOwnerTree();
32061 Roo.fly(this.wrap).highlight(
32062 tree.hlColor || "C3DAF9",
32063 {endColor: tree.hlBaseColor}
32067 collapse : function(){
32068 this.updateExpandIcon();
32069 this.ctNode.style.display = "none";
32072 animCollapse : function(callback){
32073 var ct = Roo.get(this.ctNode);
32074 ct.enableDisplayMode('block');
32077 this.animating = true;
32078 this.updateExpandIcon();
32081 callback : function(){
32082 this.animating = false;
32083 Roo.callback(callback);
32086 duration: this.node.ownerTree.duration || .25
32090 getContainer : function(){
32091 return this.ctNode;
32094 getEl : function(){
32098 appendDDGhost : function(ghostNode){
32099 ghostNode.appendChild(this.elNode.cloneNode(true));
32102 getDDRepairXY : function(){
32103 return Roo.lib.Dom.getXY(this.iconNode);
32106 onRender : function(){
32110 render : function(bulkRender){
32111 var n = this.node, a = n.attributes;
32112 var targetNode = n.parentNode ?
32113 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32115 if(!this.rendered){
32116 this.rendered = true;
32118 this.renderElements(n, a, targetNode, bulkRender);
32121 if(this.textNode.setAttributeNS){
32122 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32124 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32127 this.textNode.setAttribute("ext:qtip", a.qtip);
32129 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32132 }else if(a.qtipCfg){
32133 a.qtipCfg.target = Roo.id(this.textNode);
32134 Roo.QuickTips.register(a.qtipCfg);
32137 if(!this.node.expanded){
32138 this.updateExpandIcon();
32141 if(bulkRender === true) {
32142 targetNode.appendChild(this.wrap);
32147 renderElements : function(n, a, targetNode, bulkRender){
32148 // add some indent caching, this helps performance when rendering a large tree
32149 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32150 var t = n.getOwnerTree();
32151 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32152 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32153 var cb = typeof a.checked == 'boolean';
32154 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32155 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32156 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32157 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32158 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32159 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32160 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32161 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32162 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32163 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32166 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32167 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32168 n.nextSibling.ui.getEl(), buf.join(""));
32170 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32173 this.elNode = this.wrap.childNodes[0];
32174 this.ctNode = this.wrap.childNodes[1];
32175 var cs = this.elNode.childNodes;
32176 this.indentNode = cs[0];
32177 this.ecNode = cs[1];
32178 this.iconNode = cs[2];
32181 this.checkbox = cs[3];
32184 this.anchor = cs[index];
32185 this.textNode = cs[index].firstChild;
32188 getAnchor : function(){
32189 return this.anchor;
32192 getTextEl : function(){
32193 return this.textNode;
32196 getIconEl : function(){
32197 return this.iconNode;
32200 isChecked : function(){
32201 return this.checkbox ? this.checkbox.checked : false;
32204 updateExpandIcon : function(){
32206 var n = this.node, c1, c2;
32207 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32208 var hasChild = n.hasChildNodes();
32212 c1 = "x-tree-node-collapsed";
32213 c2 = "x-tree-node-expanded";
32216 c1 = "x-tree-node-expanded";
32217 c2 = "x-tree-node-collapsed";
32220 this.removeClass("x-tree-node-leaf");
32221 this.wasLeaf = false;
32223 if(this.c1 != c1 || this.c2 != c2){
32224 Roo.fly(this.elNode).replaceClass(c1, c2);
32225 this.c1 = c1; this.c2 = c2;
32229 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32232 this.wasLeaf = true;
32235 var ecc = "x-tree-ec-icon "+cls;
32236 if(this.ecc != ecc){
32237 this.ecNode.className = ecc;
32243 getChildIndent : function(){
32244 if(!this.childIndent){
32248 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32250 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32252 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32257 this.childIndent = buf.join("");
32259 return this.childIndent;
32262 renderIndent : function(){
32265 var p = this.node.parentNode;
32267 indent = p.ui.getChildIndent();
32269 if(this.indentMarkup != indent){ // don't rerender if not required
32270 this.indentNode.innerHTML = indent;
32271 this.indentMarkup = indent;
32273 this.updateExpandIcon();
32278 Roo.tree.RootTreeNodeUI = function(){
32279 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32281 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32282 render : function(){
32283 if(!this.rendered){
32284 var targetNode = this.node.ownerTree.innerCt.dom;
32285 this.node.expanded = true;
32286 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32287 this.wrap = this.ctNode = targetNode.firstChild;
32290 collapse : function(){
32292 expand : function(){
32296 * Ext JS Library 1.1.1
32297 * Copyright(c) 2006-2007, Ext JS, LLC.
32299 * Originally Released Under LGPL - original licence link has changed is not relivant.
32302 * <script type="text/javascript">
32305 * @class Roo.tree.TreeLoader
32306 * @extends Roo.util.Observable
32307 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32308 * nodes from a specified URL. The response must be a javascript Array definition
32309 * who's elements are node definition objects. eg:
32311 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32312 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32315 * A server request is sent, and child nodes are loaded only when a node is expanded.
32316 * The loading node's id is passed to the server under the parameter name "node" to
32317 * enable the server to produce the correct child nodes.
32319 * To pass extra parameters, an event handler may be attached to the "beforeload"
32320 * event, and the parameters specified in the TreeLoader's baseParams property:
32322 myTreeLoader.on("beforeload", function(treeLoader, node) {
32323 this.baseParams.category = node.attributes.category;
32326 * This would pass an HTTP parameter called "category" to the server containing
32327 * the value of the Node's "category" attribute.
32329 * Creates a new Treeloader.
32330 * @param {Object} config A config object containing config properties.
32332 Roo.tree.TreeLoader = function(config){
32333 this.baseParams = {};
32334 this.requestMethod = "POST";
32335 Roo.apply(this, config);
32340 * @event beforeload
32341 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32342 * @param {Object} This TreeLoader object.
32343 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32344 * @param {Object} callback The callback function specified in the {@link #load} call.
32349 * Fires when the node has been successfuly loaded.
32350 * @param {Object} This TreeLoader object.
32351 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32352 * @param {Object} response The response object containing the data from the server.
32356 * @event loadexception
32357 * Fires if the network request failed.
32358 * @param {Object} This TreeLoader object.
32359 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32360 * @param {Object} response The response object containing the data from the server.
32362 loadexception : true,
32365 * Fires before a node is created, enabling you to return custom Node types
32366 * @param {Object} This TreeLoader object.
32367 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32372 Roo.tree.TreeLoader.superclass.constructor.call(this);
32375 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32377 * @cfg {String} dataUrl The URL from which to request a Json string which
32378 * specifies an array of node definition object representing the child nodes
32382 * @cfg {Object} baseParams (optional) An object containing properties which
32383 * specify HTTP parameters to be passed to each request for child nodes.
32386 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32387 * created by this loader. If the attributes sent by the server have an attribute in this object,
32388 * they take priority.
32391 * @cfg {Object} uiProviders (optional) An object containing properties which
32393 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32394 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32395 * <i>uiProvider</i> attribute of a returned child node is a string rather
32396 * than a reference to a TreeNodeUI implementation, this that string value
32397 * is used as a property name in the uiProviders object. You can define the provider named
32398 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32403 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32404 * child nodes before loading.
32406 clearOnLoad : true,
32409 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32410 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32411 * Grid query { data : [ .....] }
32416 * @cfg {String} queryParam (optional)
32417 * Name of the query as it will be passed on the querystring (defaults to 'node')
32418 * eg. the request will be ?node=[id]
32425 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32426 * This is called automatically when a node is expanded, but may be used to reload
32427 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32428 * @param {Roo.tree.TreeNode} node
32429 * @param {Function} callback
32431 load : function(node, callback){
32432 if(this.clearOnLoad){
32433 while(node.firstChild){
32434 node.removeChild(node.firstChild);
32437 if(node.attributes.children){ // preloaded json children
32438 var cs = node.attributes.children;
32439 for(var i = 0, len = cs.length; i < len; i++){
32440 node.appendChild(this.createNode(cs[i]));
32442 if(typeof callback == "function"){
32445 }else if(this.dataUrl){
32446 this.requestData(node, callback);
32450 getParams: function(node){
32451 var buf = [], bp = this.baseParams;
32452 for(var key in bp){
32453 if(typeof bp[key] != "function"){
32454 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32457 var n = this.queryParam === false ? 'node' : this.queryParam;
32458 buf.push(n + "=", encodeURIComponent(node.id));
32459 return buf.join("");
32462 requestData : function(node, callback){
32463 if(this.fireEvent("beforeload", this, node, callback) !== false){
32464 this.transId = Roo.Ajax.request({
32465 method:this.requestMethod,
32466 url: this.dataUrl||this.url,
32467 success: this.handleResponse,
32468 failure: this.handleFailure,
32470 argument: {callback: callback, node: node},
32471 params: this.getParams(node)
32474 // if the load is cancelled, make sure we notify
32475 // the node that we are done
32476 if(typeof callback == "function"){
32482 isLoading : function(){
32483 return this.transId ? true : false;
32486 abort : function(){
32487 if(this.isLoading()){
32488 Roo.Ajax.abort(this.transId);
32493 createNode : function(attr){
32494 // apply baseAttrs, nice idea Corey!
32495 if(this.baseAttrs){
32496 Roo.applyIf(attr, this.baseAttrs);
32498 if(this.applyLoader !== false){
32499 attr.loader = this;
32501 // uiProvider = depreciated..
32503 if(typeof(attr.uiProvider) == 'string'){
32504 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32505 /** eval:var:attr */ eval(attr.uiProvider);
32507 if(typeof(this.uiProviders['default']) != 'undefined') {
32508 attr.uiProvider = this.uiProviders['default'];
32511 this.fireEvent('create', this, attr);
32513 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32515 new Roo.tree.TreeNode(attr) :
32516 new Roo.tree.AsyncTreeNode(attr));
32519 processResponse : function(response, node, callback){
32520 var json = response.responseText;
32523 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32524 if (this.root !== false) {
32528 for(var i = 0, len = o.length; i < len; i++){
32529 var n = this.createNode(o[i]);
32531 node.appendChild(n);
32534 if(typeof callback == "function"){
32535 callback(this, node);
32538 this.handleFailure(response);
32542 handleResponse : function(response){
32543 this.transId = false;
32544 var a = response.argument;
32545 this.processResponse(response, a.node, a.callback);
32546 this.fireEvent("load", this, a.node, response);
32549 handleFailure : function(response){
32550 this.transId = false;
32551 var a = response.argument;
32552 this.fireEvent("loadexception", this, a.node, response);
32553 if(typeof a.callback == "function"){
32554 a.callback(this, a.node);
32559 * Ext JS Library 1.1.1
32560 * Copyright(c) 2006-2007, Ext JS, LLC.
32562 * Originally Released Under LGPL - original licence link has changed is not relivant.
32565 * <script type="text/javascript">
32569 * @class Roo.tree.TreeFilter
32570 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32571 * @param {TreePanel} tree
32572 * @param {Object} config (optional)
32574 Roo.tree.TreeFilter = function(tree, config){
32576 this.filtered = {};
32577 Roo.apply(this, config);
32580 Roo.tree.TreeFilter.prototype = {
32587 * Filter the data by a specific attribute.
32588 * @param {String/RegExp} value Either string that the attribute value
32589 * should start with or a RegExp to test against the attribute
32590 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32591 * @param {TreeNode} startNode (optional) The node to start the filter at.
32593 filter : function(value, attr, startNode){
32594 attr = attr || "text";
32596 if(typeof value == "string"){
32597 var vlen = value.length;
32598 // auto clear empty filter
32599 if(vlen == 0 && this.clearBlank){
32603 value = value.toLowerCase();
32605 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32607 }else if(value.exec){ // regex?
32609 return value.test(n.attributes[attr]);
32612 throw 'Illegal filter type, must be string or regex';
32614 this.filterBy(f, null, startNode);
32618 * Filter by a function. The passed function will be called with each
32619 * node in the tree (or from the startNode). If the function returns true, the node is kept
32620 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32621 * @param {Function} fn The filter function
32622 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32624 filterBy : function(fn, scope, startNode){
32625 startNode = startNode || this.tree.root;
32626 if(this.autoClear){
32629 var af = this.filtered, rv = this.reverse;
32630 var f = function(n){
32631 if(n == startNode){
32637 var m = fn.call(scope || n, n);
32645 startNode.cascade(f);
32648 if(typeof id != "function"){
32650 if(n && n.parentNode){
32651 n.parentNode.removeChild(n);
32659 * Clears the current filter. Note: with the "remove" option
32660 * set a filter cannot be cleared.
32662 clear : function(){
32664 var af = this.filtered;
32666 if(typeof id != "function"){
32673 this.filtered = {};
32678 * Ext JS Library 1.1.1
32679 * Copyright(c) 2006-2007, Ext JS, LLC.
32681 * Originally Released Under LGPL - original licence link has changed is not relivant.
32684 * <script type="text/javascript">
32689 * @class Roo.tree.TreeSorter
32690 * Provides sorting of nodes in a TreePanel
32692 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32693 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32694 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32695 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32696 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32697 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32699 * @param {TreePanel} tree
32700 * @param {Object} config
32702 Roo.tree.TreeSorter = function(tree, config){
32703 Roo.apply(this, config);
32704 tree.on("beforechildrenrendered", this.doSort, this);
32705 tree.on("append", this.updateSort, this);
32706 tree.on("insert", this.updateSort, this);
32708 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32709 var p = this.property || "text";
32710 var sortType = this.sortType;
32711 var fs = this.folderSort;
32712 var cs = this.caseSensitive === true;
32713 var leafAttr = this.leafAttr || 'leaf';
32715 this.sortFn = function(n1, n2){
32717 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32720 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32724 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32725 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32727 return dsc ? +1 : -1;
32729 return dsc ? -1 : +1;
32736 Roo.tree.TreeSorter.prototype = {
32737 doSort : function(node){
32738 node.sort(this.sortFn);
32741 compareNodes : function(n1, n2){
32742 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
32745 updateSort : function(tree, node){
32746 if(node.childrenRendered){
32747 this.doSort.defer(1, this, [node]);
32752 * Ext JS Library 1.1.1
32753 * Copyright(c) 2006-2007, Ext JS, LLC.
32755 * Originally Released Under LGPL - original licence link has changed is not relivant.
32758 * <script type="text/javascript">
32761 if(Roo.dd.DropZone){
32763 Roo.tree.TreeDropZone = function(tree, config){
32764 this.allowParentInsert = false;
32765 this.allowContainerDrop = false;
32766 this.appendOnly = false;
32767 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
32769 this.lastInsertClass = "x-tree-no-status";
32770 this.dragOverData = {};
32773 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
32774 ddGroup : "TreeDD",
32776 expandDelay : 1000,
32778 expandNode : function(node){
32779 if(node.hasChildNodes() && !node.isExpanded()){
32780 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
32784 queueExpand : function(node){
32785 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
32788 cancelExpand : function(){
32789 if(this.expandProcId){
32790 clearTimeout(this.expandProcId);
32791 this.expandProcId = false;
32795 isValidDropPoint : function(n, pt, dd, e, data){
32796 if(!n || !data){ return false; }
32797 var targetNode = n.node;
32798 var dropNode = data.node;
32799 // default drop rules
32800 if(!(targetNode && targetNode.isTarget && pt)){
32803 if(pt == "append" && targetNode.allowChildren === false){
32806 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
32809 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
32812 // reuse the object
32813 var overEvent = this.dragOverData;
32814 overEvent.tree = this.tree;
32815 overEvent.target = targetNode;
32816 overEvent.data = data;
32817 overEvent.point = pt;
32818 overEvent.source = dd;
32819 overEvent.rawEvent = e;
32820 overEvent.dropNode = dropNode;
32821 overEvent.cancel = false;
32822 var result = this.tree.fireEvent("nodedragover", overEvent);
32823 return overEvent.cancel === false && result !== false;
32826 getDropPoint : function(e, n, dd){
32829 return tn.allowChildren !== false ? "append" : false; // always append for root
32831 var dragEl = n.ddel;
32832 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
32833 var y = Roo.lib.Event.getPageY(e);
32834 var noAppend = tn.allowChildren === false || tn.isLeaf();
32835 if(this.appendOnly || tn.parentNode.allowChildren === false){
32836 return noAppend ? false : "append";
32838 var noBelow = false;
32839 if(!this.allowParentInsert){
32840 noBelow = tn.hasChildNodes() && tn.isExpanded();
32842 var q = (b - t) / (noAppend ? 2 : 3);
32843 if(y >= t && y < (t + q)){
32845 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
32852 onNodeEnter : function(n, dd, e, data){
32853 this.cancelExpand();
32856 onNodeOver : function(n, dd, e, data){
32857 var pt = this.getDropPoint(e, n, dd);
32860 // auto node expand check
32861 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
32862 this.queueExpand(node);
32863 }else if(pt != "append"){
32864 this.cancelExpand();
32867 // set the insert point style on the target node
32868 var returnCls = this.dropNotAllowed;
32869 if(this.isValidDropPoint(n, pt, dd, e, data)){
32874 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
32875 cls = "x-tree-drag-insert-above";
32876 }else if(pt == "below"){
32877 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
32878 cls = "x-tree-drag-insert-below";
32880 returnCls = "x-tree-drop-ok-append";
32881 cls = "x-tree-drag-append";
32883 if(this.lastInsertClass != cls){
32884 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
32885 this.lastInsertClass = cls;
32892 onNodeOut : function(n, dd, e, data){
32893 this.cancelExpand();
32894 this.removeDropIndicators(n);
32897 onNodeDrop : function(n, dd, e, data){
32898 var point = this.getDropPoint(e, n, dd);
32899 var targetNode = n.node;
32900 targetNode.ui.startDrop();
32901 if(!this.isValidDropPoint(n, point, dd, e, data)){
32902 targetNode.ui.endDrop();
32905 // first try to find the drop node
32906 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
32909 target: targetNode,
32914 dropNode: dropNode,
32917 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
32918 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
32919 targetNode.ui.endDrop();
32922 // allow target changing
32923 targetNode = dropEvent.target;
32924 if(point == "append" && !targetNode.isExpanded()){
32925 targetNode.expand(false, null, function(){
32926 this.completeDrop(dropEvent);
32927 }.createDelegate(this));
32929 this.completeDrop(dropEvent);
32934 completeDrop : function(de){
32935 var ns = de.dropNode, p = de.point, t = de.target;
32936 if(!(ns instanceof Array)){
32940 for(var i = 0, len = ns.length; i < len; i++){
32943 t.parentNode.insertBefore(n, t);
32944 }else if(p == "below"){
32945 t.parentNode.insertBefore(n, t.nextSibling);
32951 if(this.tree.hlDrop){
32955 this.tree.fireEvent("nodedrop", de);
32958 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
32959 if(this.tree.hlDrop){
32960 dropNode.ui.focus();
32961 dropNode.ui.highlight();
32963 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
32966 getTree : function(){
32970 removeDropIndicators : function(n){
32973 Roo.fly(el).removeClass([
32974 "x-tree-drag-insert-above",
32975 "x-tree-drag-insert-below",
32976 "x-tree-drag-append"]);
32977 this.lastInsertClass = "_noclass";
32981 beforeDragDrop : function(target, e, id){
32982 this.cancelExpand();
32986 afterRepair : function(data){
32987 if(data && Roo.enableFx){
32988 data.node.ui.highlight();
32996 * Ext JS Library 1.1.1
32997 * Copyright(c) 2006-2007, Ext JS, LLC.
32999 * Originally Released Under LGPL - original licence link has changed is not relivant.
33002 * <script type="text/javascript">
33006 if(Roo.dd.DragZone){
33007 Roo.tree.TreeDragZone = function(tree, config){
33008 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33012 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33013 ddGroup : "TreeDD",
33015 onBeforeDrag : function(data, e){
33017 return n && n.draggable && !n.disabled;
33020 onInitDrag : function(e){
33021 var data = this.dragData;
33022 this.tree.getSelectionModel().select(data.node);
33023 this.proxy.update("");
33024 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33025 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33028 getRepairXY : function(e, data){
33029 return data.node.ui.getDDRepairXY();
33032 onEndDrag : function(data, e){
33033 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33036 onValidDrop : function(dd, e, id){
33037 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33041 beforeInvalidDrop : function(e, id){
33042 // this scrolls the original position back into view
33043 var sm = this.tree.getSelectionModel();
33044 sm.clearSelections();
33045 sm.select(this.dragData.node);
33050 * Ext JS Library 1.1.1
33051 * Copyright(c) 2006-2007, Ext JS, LLC.
33053 * Originally Released Under LGPL - original licence link has changed is not relivant.
33056 * <script type="text/javascript">
33059 * @class Roo.tree.TreeEditor
33060 * @extends Roo.Editor
33061 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33062 * as the editor field.
33064 * @param {TreePanel} tree
33065 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33067 Roo.tree.TreeEditor = function(tree, config){
33068 config = config || {};
33069 var field = config.events ? config : new Roo.form.TextField(config);
33070 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33074 tree.on('beforeclick', this.beforeNodeClick, this);
33075 tree.getTreeEl().on('mousedown', this.hide, this);
33076 this.on('complete', this.updateNode, this);
33077 this.on('beforestartedit', this.fitToTree, this);
33078 this.on('startedit', this.bindScroll, this, {delay:10});
33079 this.on('specialkey', this.onSpecialKey, this);
33082 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33084 * @cfg {String} alignment
33085 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33091 * @cfg {Boolean} hideEl
33092 * True to hide the bound element while the editor is displayed (defaults to false)
33096 * @cfg {String} cls
33097 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33099 cls: "x-small-editor x-tree-editor",
33101 * @cfg {Boolean} shim
33102 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33108 * @cfg {Number} maxWidth
33109 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33110 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33111 * scroll and client offsets into account prior to each edit.
33118 fitToTree : function(ed, el){
33119 var td = this.tree.getTreeEl().dom, nd = el.dom;
33120 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33121 td.scrollLeft = nd.offsetLeft;
33125 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33126 this.setSize(w, '');
33130 triggerEdit : function(node){
33131 this.completeEdit();
33132 this.editNode = node;
33133 this.startEdit(node.ui.textNode, node.text);
33137 bindScroll : function(){
33138 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33142 beforeNodeClick : function(node, e){
33143 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33144 this.lastClick = new Date();
33145 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33147 this.triggerEdit(node);
33153 updateNode : function(ed, value){
33154 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33155 this.editNode.setText(value);
33159 onHide : function(){
33160 Roo.tree.TreeEditor.superclass.onHide.call(this);
33162 this.editNode.ui.focus();
33167 onSpecialKey : function(field, e){
33168 var k = e.getKey();
33172 }else if(k == e.ENTER && !e.hasModifier()){
33174 this.completeEdit();
33177 });//<Script type="text/javascript">
33180 * Ext JS Library 1.1.1
33181 * Copyright(c) 2006-2007, Ext JS, LLC.
33183 * Originally Released Under LGPL - original licence link has changed is not relivant.
33186 * <script type="text/javascript">
33190 * Not documented??? - probably should be...
33193 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33194 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33196 renderElements : function(n, a, targetNode, bulkRender){
33197 //consel.log("renderElements?");
33198 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33200 var t = n.getOwnerTree();
33201 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33203 var cols = t.columns;
33204 var bw = t.borderWidth;
33206 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33207 var cb = typeof a.checked == "boolean";
33208 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33209 var colcls = 'x-t-' + tid + '-c0';
33211 '<li class="x-tree-node">',
33214 '<div class="x-tree-node-el ', a.cls,'">',
33216 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33219 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33220 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33221 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33222 (a.icon ? ' x-tree-node-inline-icon' : ''),
33223 (a.iconCls ? ' '+a.iconCls : ''),
33224 '" unselectable="on" />',
33225 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33226 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33228 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33229 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33230 '<span unselectable="on" qtip="' + tx + '">',
33234 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33235 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33238 for(var i = 1, len = cols.length; i < len; i++){
33240 colcls = 'x-t-' + tid + '-c' +i;
33241 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33242 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33243 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33249 '<div class="x-clear"></div></div>',
33250 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33253 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33254 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33255 n.nextSibling.ui.getEl(), buf.join(""));
33257 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33259 var el = this.wrap.firstChild;
33261 this.elNode = el.firstChild;
33262 this.ranchor = el.childNodes[1];
33263 this.ctNode = this.wrap.childNodes[1];
33264 var cs = el.firstChild.childNodes;
33265 this.indentNode = cs[0];
33266 this.ecNode = cs[1];
33267 this.iconNode = cs[2];
33270 this.checkbox = cs[3];
33273 this.anchor = cs[index];
33275 this.textNode = cs[index].firstChild;
33277 //el.on("click", this.onClick, this);
33278 //el.on("dblclick", this.onDblClick, this);
33281 // console.log(this);
33283 initEvents : function(){
33284 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33287 var a = this.ranchor;
33289 var el = Roo.get(a);
33291 if(Roo.isOpera){ // opera render bug ignores the CSS
33292 el.setStyle("text-decoration", "none");
33295 el.on("click", this.onClick, this);
33296 el.on("dblclick", this.onDblClick, this);
33297 el.on("contextmenu", this.onContextMenu, this);
33301 /*onSelectedChange : function(state){
33304 this.addClass("x-tree-selected");
33307 this.removeClass("x-tree-selected");
33310 addClass : function(cls){
33312 Roo.fly(this.elRow).addClass(cls);
33318 removeClass : function(cls){
33320 Roo.fly(this.elRow).removeClass(cls);
33326 });//<Script type="text/javascript">
33330 * Ext JS Library 1.1.1
33331 * Copyright(c) 2006-2007, Ext JS, LLC.
33333 * Originally Released Under LGPL - original licence link has changed is not relivant.
33336 * <script type="text/javascript">
33341 * @class Roo.tree.ColumnTree
33342 * @extends Roo.data.TreePanel
33343 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33344 * @cfg {int} borderWidth compined right/left border allowance
33346 * @param {String/HTMLElement/Element} el The container element
33347 * @param {Object} config
33349 Roo.tree.ColumnTree = function(el, config)
33351 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33355 * Fire this event on a container when it resizes
33356 * @param {int} w Width
33357 * @param {int} h Height
33361 this.on('resize', this.onResize, this);
33364 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33368 borderWidth: Roo.isBorderBox ? 0 : 2,
33371 render : function(){
33372 // add the header.....
33374 Roo.tree.ColumnTree.superclass.render.apply(this);
33376 this.el.addClass('x-column-tree');
33378 this.headers = this.el.createChild(
33379 {cls:'x-tree-headers'},this.innerCt.dom);
33381 var cols = this.columns, c;
33382 var totalWidth = 0;
33384 var len = cols.length;
33385 for(var i = 0; i < len; i++){
33387 totalWidth += c.width;
33388 this.headEls.push(this.headers.createChild({
33389 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33391 cls:'x-tree-hd-text',
33394 style:'width:'+(c.width-this.borderWidth)+'px;'
33397 this.headers.createChild({cls:'x-clear'});
33398 // prevent floats from wrapping when clipped
33399 this.headers.setWidth(totalWidth);
33400 //this.innerCt.setWidth(totalWidth);
33401 this.innerCt.setStyle({ overflow: 'auto' });
33402 this.onResize(this.width, this.height);
33406 onResize : function(w,h)
33411 this.innerCt.setWidth(this.width);
33412 this.innerCt.setHeight(this.height-20);
33415 var cols = this.columns, c;
33416 var totalWidth = 0;
33418 var len = cols.length;
33419 for(var i = 0; i < len; i++){
33421 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33422 // it's the expander..
33423 expEl = this.headEls[i];
33426 totalWidth += c.width;
33430 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33432 this.headers.setWidth(w-20);
33441 * Ext JS Library 1.1.1
33442 * Copyright(c) 2006-2007, Ext JS, LLC.
33444 * Originally Released Under LGPL - original licence link has changed is not relivant.
33447 * <script type="text/javascript">
33451 * @class Roo.menu.Menu
33452 * @extends Roo.util.Observable
33453 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33454 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33456 * Creates a new Menu
33457 * @param {Object} config Configuration options
33459 Roo.menu.Menu = function(config){
33460 Roo.apply(this, config);
33461 this.id = this.id || Roo.id();
33464 * @event beforeshow
33465 * Fires before this menu is displayed
33466 * @param {Roo.menu.Menu} this
33470 * @event beforehide
33471 * Fires before this menu is hidden
33472 * @param {Roo.menu.Menu} this
33477 * Fires after this menu is displayed
33478 * @param {Roo.menu.Menu} this
33483 * Fires after this menu is hidden
33484 * @param {Roo.menu.Menu} this
33489 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33490 * @param {Roo.menu.Menu} this
33491 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33492 * @param {Roo.EventObject} e
33497 * Fires when the mouse is hovering over this menu
33498 * @param {Roo.menu.Menu} this
33499 * @param {Roo.EventObject} e
33500 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33505 * Fires when the mouse exits this menu
33506 * @param {Roo.menu.Menu} this
33507 * @param {Roo.EventObject} e
33508 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33513 * Fires when a menu item contained in this menu is clicked
33514 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33515 * @param {Roo.EventObject} e
33519 if (this.registerMenu) {
33520 Roo.menu.MenuMgr.register(this);
33523 var mis = this.items;
33524 this.items = new Roo.util.MixedCollection();
33526 this.add.apply(this, mis);
33530 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33532 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33536 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33537 * for bottom-right shadow (defaults to "sides")
33541 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33542 * this menu (defaults to "tl-tr?")
33544 subMenuAlign : "tl-tr?",
33546 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33547 * relative to its element of origin (defaults to "tl-bl?")
33549 defaultAlign : "tl-bl?",
33551 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33553 allowOtherMenus : false,
33555 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33557 registerMenu : true,
33562 render : function(){
33566 var el = this.el = new Roo.Layer({
33568 shadow:this.shadow,
33570 parentEl: this.parentEl || document.body,
33574 this.keyNav = new Roo.menu.MenuNav(this);
33577 el.addClass("x-menu-plain");
33580 el.addClass(this.cls);
33582 // generic focus element
33583 this.focusEl = el.createChild({
33584 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33586 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33587 ul.on("click", this.onClick, this);
33588 ul.on("mouseover", this.onMouseOver, this);
33589 ul.on("mouseout", this.onMouseOut, this);
33590 this.items.each(function(item){
33591 var li = document.createElement("li");
33592 li.className = "x-menu-list-item";
33593 ul.dom.appendChild(li);
33594 item.render(li, this);
33601 autoWidth : function(){
33602 var el = this.el, ul = this.ul;
33606 var w = this.width;
33609 }else if(Roo.isIE){
33610 el.setWidth(this.minWidth);
33611 var t = el.dom.offsetWidth; // force recalc
33612 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33617 delayAutoWidth : function(){
33620 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33622 this.awTask.delay(20);
33627 findTargetItem : function(e){
33628 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33629 if(t && t.menuItemId){
33630 return this.items.get(t.menuItemId);
33635 onClick : function(e){
33637 if(t = this.findTargetItem(e)){
33639 this.fireEvent("click", this, t, e);
33644 setActiveItem : function(item, autoExpand){
33645 if(item != this.activeItem){
33646 if(this.activeItem){
33647 this.activeItem.deactivate();
33649 this.activeItem = item;
33650 item.activate(autoExpand);
33651 }else if(autoExpand){
33657 tryActivate : function(start, step){
33658 var items = this.items;
33659 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33660 var item = items.get(i);
33661 if(!item.disabled && item.canActivate){
33662 this.setActiveItem(item, false);
33670 onMouseOver : function(e){
33672 if(t = this.findTargetItem(e)){
33673 if(t.canActivate && !t.disabled){
33674 this.setActiveItem(t, true);
33677 this.fireEvent("mouseover", this, e, t);
33681 onMouseOut : function(e){
33683 if(t = this.findTargetItem(e)){
33684 if(t == this.activeItem && t.shouldDeactivate(e)){
33685 this.activeItem.deactivate();
33686 delete this.activeItem;
33689 this.fireEvent("mouseout", this, e, t);
33693 * Read-only. Returns true if the menu is currently displayed, else false.
33696 isVisible : function(){
33697 return this.el && !this.hidden;
33701 * Displays this menu relative to another element
33702 * @param {String/HTMLElement/Roo.Element} element The element to align to
33703 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33704 * the element (defaults to this.defaultAlign)
33705 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33707 show : function(el, pos, parentMenu){
33708 this.parentMenu = parentMenu;
33712 this.fireEvent("beforeshow", this);
33713 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33717 * Displays this menu at a specific xy position
33718 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33719 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33721 showAt : function(xy, parentMenu, /* private: */_e){
33722 this.parentMenu = parentMenu;
33727 this.fireEvent("beforeshow", this);
33728 xy = this.el.adjustForConstraints(xy);
33732 this.hidden = false;
33734 this.fireEvent("show", this);
33737 focus : function(){
33739 this.doFocus.defer(50, this);
33743 doFocus : function(){
33745 this.focusEl.focus();
33750 * Hides this menu and optionally all parent menus
33751 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
33753 hide : function(deep){
33754 if(this.el && this.isVisible()){
33755 this.fireEvent("beforehide", this);
33756 if(this.activeItem){
33757 this.activeItem.deactivate();
33758 this.activeItem = null;
33761 this.hidden = true;
33762 this.fireEvent("hide", this);
33764 if(deep === true && this.parentMenu){
33765 this.parentMenu.hide(true);
33770 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
33771 * Any of the following are valid:
33773 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
33774 * <li>An HTMLElement object which will be converted to a menu item</li>
33775 * <li>A menu item config object that will be created as a new menu item</li>
33776 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
33777 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
33782 var menu = new Roo.menu.Menu();
33784 // Create a menu item to add by reference
33785 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
33787 // Add a bunch of items at once using different methods.
33788 // Only the last item added will be returned.
33789 var item = menu.add(
33790 menuItem, // add existing item by ref
33791 'Dynamic Item', // new TextItem
33792 '-', // new separator
33793 { text: 'Config Item' } // new item by config
33796 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
33797 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
33800 var a = arguments, l = a.length, item;
33801 for(var i = 0; i < l; i++){
33803 if(el.render){ // some kind of Item
33804 item = this.addItem(el);
33805 }else if(typeof el == "string"){ // string
33806 if(el == "separator" || el == "-"){
33807 item = this.addSeparator();
33809 item = this.addText(el);
33811 }else if(el.tagName || el.el){ // element
33812 item = this.addElement(el);
33813 }else if(typeof el == "object"){ // must be menu item config?
33814 item = this.addMenuItem(el);
33821 * Returns this menu's underlying {@link Roo.Element} object
33822 * @return {Roo.Element} The element
33824 getEl : function(){
33832 * Adds a separator bar to the menu
33833 * @return {Roo.menu.Item} The menu item that was added
33835 addSeparator : function(){
33836 return this.addItem(new Roo.menu.Separator());
33840 * Adds an {@link Roo.Element} object to the menu
33841 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
33842 * @return {Roo.menu.Item} The menu item that was added
33844 addElement : function(el){
33845 return this.addItem(new Roo.menu.BaseItem(el));
33849 * Adds an existing object based on {@link Roo.menu.Item} to the menu
33850 * @param {Roo.menu.Item} item The menu item to add
33851 * @return {Roo.menu.Item} The menu item that was added
33853 addItem : function(item){
33854 this.items.add(item);
33856 var li = document.createElement("li");
33857 li.className = "x-menu-list-item";
33858 this.ul.dom.appendChild(li);
33859 item.render(li, this);
33860 this.delayAutoWidth();
33866 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
33867 * @param {Object} config A MenuItem config object
33868 * @return {Roo.menu.Item} The menu item that was added
33870 addMenuItem : function(config){
33871 if(!(config instanceof Roo.menu.Item)){
33872 if(typeof config.checked == "boolean"){ // must be check menu item config?
33873 config = new Roo.menu.CheckItem(config);
33875 config = new Roo.menu.Item(config);
33878 return this.addItem(config);
33882 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
33883 * @param {String} text The text to display in the menu item
33884 * @return {Roo.menu.Item} The menu item that was added
33886 addText : function(text){
33887 return this.addItem(new Roo.menu.TextItem(text));
33891 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
33892 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
33893 * @param {Roo.menu.Item} item The menu item to add
33894 * @return {Roo.menu.Item} The menu item that was added
33896 insert : function(index, item){
33897 this.items.insert(index, item);
33899 var li = document.createElement("li");
33900 li.className = "x-menu-list-item";
33901 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
33902 item.render(li, this);
33903 this.delayAutoWidth();
33909 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
33910 * @param {Roo.menu.Item} item The menu item to remove
33912 remove : function(item){
33913 this.items.removeKey(item.id);
33918 * Removes and destroys all items in the menu
33920 removeAll : function(){
33922 while(f = this.items.first()){
33928 // MenuNav is a private utility class used internally by the Menu
33929 Roo.menu.MenuNav = function(menu){
33930 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
33931 this.scope = this.menu = menu;
33934 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
33935 doRelay : function(e, h){
33936 var k = e.getKey();
33937 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
33938 this.menu.tryActivate(0, 1);
33941 return h.call(this.scope || this, e, this.menu);
33944 up : function(e, m){
33945 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
33946 m.tryActivate(m.items.length-1, -1);
33950 down : function(e, m){
33951 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
33952 m.tryActivate(0, 1);
33956 right : function(e, m){
33958 m.activeItem.expandMenu(true);
33962 left : function(e, m){
33964 if(m.parentMenu && m.parentMenu.activeItem){
33965 m.parentMenu.activeItem.activate();
33969 enter : function(e, m){
33971 e.stopPropagation();
33972 m.activeItem.onClick(e);
33973 m.fireEvent("click", this, m.activeItem);
33979 * Ext JS Library 1.1.1
33980 * Copyright(c) 2006-2007, Ext JS, LLC.
33982 * Originally Released Under LGPL - original licence link has changed is not relivant.
33985 * <script type="text/javascript">
33989 * @class Roo.menu.MenuMgr
33990 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
33993 Roo.menu.MenuMgr = function(){
33994 var menus, active, groups = {}, attached = false, lastShow = new Date();
33996 // private - called when first menu is created
33999 active = new Roo.util.MixedCollection();
34000 Roo.get(document).addKeyListener(27, function(){
34001 if(active.length > 0){
34008 function hideAll(){
34009 if(active && active.length > 0){
34010 var c = active.clone();
34011 c.each(function(m){
34018 function onHide(m){
34020 if(active.length < 1){
34021 Roo.get(document).un("mousedown", onMouseDown);
34027 function onShow(m){
34028 var last = active.last();
34029 lastShow = new Date();
34032 Roo.get(document).on("mousedown", onMouseDown);
34036 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34037 m.parentMenu.activeChild = m;
34038 }else if(last && last.isVisible()){
34039 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34044 function onBeforeHide(m){
34046 m.activeChild.hide();
34048 if(m.autoHideTimer){
34049 clearTimeout(m.autoHideTimer);
34050 delete m.autoHideTimer;
34055 function onBeforeShow(m){
34056 var pm = m.parentMenu;
34057 if(!pm && !m.allowOtherMenus){
34059 }else if(pm && pm.activeChild && active != m){
34060 pm.activeChild.hide();
34065 function onMouseDown(e){
34066 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34072 function onBeforeCheck(mi, state){
34074 var g = groups[mi.group];
34075 for(var i = 0, l = g.length; i < l; i++){
34077 g[i].setChecked(false);
34086 * Hides all menus that are currently visible
34088 hideAll : function(){
34093 register : function(menu){
34097 menus[menu.id] = menu;
34098 menu.on("beforehide", onBeforeHide);
34099 menu.on("hide", onHide);
34100 menu.on("beforeshow", onBeforeShow);
34101 menu.on("show", onShow);
34102 var g = menu.group;
34103 if(g && menu.events["checkchange"]){
34107 groups[g].push(menu);
34108 menu.on("checkchange", onCheck);
34113 * Returns a {@link Roo.menu.Menu} object
34114 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34115 * be used to generate and return a new Menu instance.
34117 get : function(menu){
34118 if(typeof menu == "string"){ // menu id
34119 return menus[menu];
34120 }else if(menu.events){ // menu instance
34122 }else if(typeof menu.length == 'number'){ // array of menu items?
34123 return new Roo.menu.Menu({items:menu});
34124 }else{ // otherwise, must be a config
34125 return new Roo.menu.Menu(menu);
34130 unregister : function(menu){
34131 delete menus[menu.id];
34132 menu.un("beforehide", onBeforeHide);
34133 menu.un("hide", onHide);
34134 menu.un("beforeshow", onBeforeShow);
34135 menu.un("show", onShow);
34136 var g = menu.group;
34137 if(g && menu.events["checkchange"]){
34138 groups[g].remove(menu);
34139 menu.un("checkchange", onCheck);
34144 registerCheckable : function(menuItem){
34145 var g = menuItem.group;
34150 groups[g].push(menuItem);
34151 menuItem.on("beforecheckchange", onBeforeCheck);
34156 unregisterCheckable : function(menuItem){
34157 var g = menuItem.group;
34159 groups[g].remove(menuItem);
34160 menuItem.un("beforecheckchange", onBeforeCheck);
34166 * Ext JS Library 1.1.1
34167 * Copyright(c) 2006-2007, Ext JS, LLC.
34169 * Originally Released Under LGPL - original licence link has changed is not relivant.
34172 * <script type="text/javascript">
34177 * @class Roo.menu.BaseItem
34178 * @extends Roo.Component
34179 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34180 * management and base configuration options shared by all menu components.
34182 * Creates a new BaseItem
34183 * @param {Object} config Configuration options
34185 Roo.menu.BaseItem = function(config){
34186 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34191 * Fires when this item is clicked
34192 * @param {Roo.menu.BaseItem} this
34193 * @param {Roo.EventObject} e
34198 * Fires when this item is activated
34199 * @param {Roo.menu.BaseItem} this
34203 * @event deactivate
34204 * Fires when this item is deactivated
34205 * @param {Roo.menu.BaseItem} this
34211 this.on("click", this.handler, this.scope, true);
34215 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34217 * @cfg {Function} handler
34218 * A function that will handle the click event of this menu item (defaults to undefined)
34221 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34223 canActivate : false,
34225 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34227 activeClass : "x-menu-item-active",
34229 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34231 hideOnClick : true,
34233 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34238 ctype: "Roo.menu.BaseItem",
34241 actionMode : "container",
34244 render : function(container, parentMenu){
34245 this.parentMenu = parentMenu;
34246 Roo.menu.BaseItem.superclass.render.call(this, container);
34247 this.container.menuItemId = this.id;
34251 onRender : function(container, position){
34252 this.el = Roo.get(this.el);
34253 container.dom.appendChild(this.el.dom);
34257 onClick : function(e){
34258 if(!this.disabled && this.fireEvent("click", this, e) !== false
34259 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34260 this.handleClick(e);
34267 activate : function(){
34271 var li = this.container;
34272 li.addClass(this.activeClass);
34273 this.region = li.getRegion().adjust(2, 2, -2, -2);
34274 this.fireEvent("activate", this);
34279 deactivate : function(){
34280 this.container.removeClass(this.activeClass);
34281 this.fireEvent("deactivate", this);
34285 shouldDeactivate : function(e){
34286 return !this.region || !this.region.contains(e.getPoint());
34290 handleClick : function(e){
34291 if(this.hideOnClick){
34292 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34297 expandMenu : function(autoActivate){
34302 hideMenu : function(){
34307 * Ext JS Library 1.1.1
34308 * Copyright(c) 2006-2007, Ext JS, LLC.
34310 * Originally Released Under LGPL - original licence link has changed is not relivant.
34313 * <script type="text/javascript">
34317 * @class Roo.menu.Adapter
34318 * @extends Roo.menu.BaseItem
34319 * 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.
34320 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34322 * Creates a new Adapter
34323 * @param {Object} config Configuration options
34325 Roo.menu.Adapter = function(component, config){
34326 Roo.menu.Adapter.superclass.constructor.call(this, config);
34327 this.component = component;
34329 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34331 canActivate : true,
34334 onRender : function(container, position){
34335 this.component.render(container);
34336 this.el = this.component.getEl();
34340 activate : function(){
34344 this.component.focus();
34345 this.fireEvent("activate", this);
34350 deactivate : function(){
34351 this.fireEvent("deactivate", this);
34355 disable : function(){
34356 this.component.disable();
34357 Roo.menu.Adapter.superclass.disable.call(this);
34361 enable : function(){
34362 this.component.enable();
34363 Roo.menu.Adapter.superclass.enable.call(this);
34367 * Ext JS Library 1.1.1
34368 * Copyright(c) 2006-2007, Ext JS, LLC.
34370 * Originally Released Under LGPL - original licence link has changed is not relivant.
34373 * <script type="text/javascript">
34377 * @class Roo.menu.TextItem
34378 * @extends Roo.menu.BaseItem
34379 * Adds a static text string to a menu, usually used as either a heading or group separator.
34381 * Creates a new TextItem
34382 * @param {String} text The text to display
34384 Roo.menu.TextItem = function(text){
34386 Roo.menu.TextItem.superclass.constructor.call(this);
34389 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34391 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34393 hideOnClick : false,
34395 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34397 itemCls : "x-menu-text",
34400 onRender : function(){
34401 var s = document.createElement("span");
34402 s.className = this.itemCls;
34403 s.innerHTML = this.text;
34405 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34409 * Ext JS Library 1.1.1
34410 * Copyright(c) 2006-2007, Ext JS, LLC.
34412 * Originally Released Under LGPL - original licence link has changed is not relivant.
34415 * <script type="text/javascript">
34419 * @class Roo.menu.Separator
34420 * @extends Roo.menu.BaseItem
34421 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34422 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34424 * @param {Object} config Configuration options
34426 Roo.menu.Separator = function(config){
34427 Roo.menu.Separator.superclass.constructor.call(this, config);
34430 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34432 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34434 itemCls : "x-menu-sep",
34436 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34438 hideOnClick : false,
34441 onRender : function(li){
34442 var s = document.createElement("span");
34443 s.className = this.itemCls;
34444 s.innerHTML = " ";
34446 li.addClass("x-menu-sep-li");
34447 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34451 * Ext JS Library 1.1.1
34452 * Copyright(c) 2006-2007, Ext JS, LLC.
34454 * Originally Released Under LGPL - original licence link has changed is not relivant.
34457 * <script type="text/javascript">
34460 * @class Roo.menu.Item
34461 * @extends Roo.menu.BaseItem
34462 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34463 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34464 * activation and click handling.
34466 * Creates a new Item
34467 * @param {Object} config Configuration options
34469 Roo.menu.Item = function(config){
34470 Roo.menu.Item.superclass.constructor.call(this, config);
34472 this.menu = Roo.menu.MenuMgr.get(this.menu);
34475 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34477 * @cfg {String} icon
34478 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34481 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34483 itemCls : "x-menu-item",
34485 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34487 canActivate : true,
34489 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34492 // doc'd in BaseItem
34496 ctype: "Roo.menu.Item",
34499 onRender : function(container, position){
34500 var el = document.createElement("a");
34501 el.hideFocus = true;
34502 el.unselectable = "on";
34503 el.href = this.href || "#";
34504 if(this.hrefTarget){
34505 el.target = this.hrefTarget;
34507 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34508 el.innerHTML = String.format(
34509 '<img src="{0}" class="x-menu-item-icon {2}" />{1}',
34510 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || '');
34512 Roo.menu.Item.superclass.onRender.call(this, container, position);
34516 * Sets the text to display in this menu item
34517 * @param {String} text The text to display
34519 setText : function(text){
34522 this.el.update(String.format(
34523 '<img src="{0}" class="x-menu-item-icon {2}">{1}',
34524 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34525 this.parentMenu.autoWidth();
34530 handleClick : function(e){
34531 if(!this.href){ // if no link defined, stop the event automatically
34534 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34538 activate : function(autoExpand){
34539 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34549 shouldDeactivate : function(e){
34550 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34551 if(this.menu && this.menu.isVisible()){
34552 return !this.menu.getEl().getRegion().contains(e.getPoint());
34560 deactivate : function(){
34561 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34566 expandMenu : function(autoActivate){
34567 if(!this.disabled && this.menu){
34568 clearTimeout(this.hideTimer);
34569 delete this.hideTimer;
34570 if(!this.menu.isVisible() && !this.showTimer){
34571 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34572 }else if (this.menu.isVisible() && autoActivate){
34573 this.menu.tryActivate(0, 1);
34579 deferExpand : function(autoActivate){
34580 delete this.showTimer;
34581 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34583 this.menu.tryActivate(0, 1);
34588 hideMenu : function(){
34589 clearTimeout(this.showTimer);
34590 delete this.showTimer;
34591 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34592 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34597 deferHide : function(){
34598 delete this.hideTimer;
34603 * Ext JS Library 1.1.1
34604 * Copyright(c) 2006-2007, Ext JS, LLC.
34606 * Originally Released Under LGPL - original licence link has changed is not relivant.
34609 * <script type="text/javascript">
34613 * @class Roo.menu.CheckItem
34614 * @extends Roo.menu.Item
34615 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34617 * Creates a new CheckItem
34618 * @param {Object} config Configuration options
34620 Roo.menu.CheckItem = function(config){
34621 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34624 * @event beforecheckchange
34625 * Fires before the checked value is set, providing an opportunity to cancel if needed
34626 * @param {Roo.menu.CheckItem} this
34627 * @param {Boolean} checked The new checked value that will be set
34629 "beforecheckchange" : true,
34631 * @event checkchange
34632 * Fires after the checked value has been set
34633 * @param {Roo.menu.CheckItem} this
34634 * @param {Boolean} checked The checked value that was set
34636 "checkchange" : true
34638 if(this.checkHandler){
34639 this.on('checkchange', this.checkHandler, this.scope);
34642 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34644 * @cfg {String} group
34645 * All check items with the same group name will automatically be grouped into a single-select
34646 * radio button group (defaults to '')
34649 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34651 itemCls : "x-menu-item x-menu-check-item",
34653 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34655 groupClass : "x-menu-group-item",
34658 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34659 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34660 * initialized with checked = true will be rendered as checked.
34665 ctype: "Roo.menu.CheckItem",
34668 onRender : function(c){
34669 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34671 this.el.addClass(this.groupClass);
34673 Roo.menu.MenuMgr.registerCheckable(this);
34675 this.checked = false;
34676 this.setChecked(true, true);
34681 destroy : function(){
34683 Roo.menu.MenuMgr.unregisterCheckable(this);
34685 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34689 * Set the checked state of this item
34690 * @param {Boolean} checked The new checked value
34691 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
34693 setChecked : function(state, suppressEvent){
34694 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
34695 if(this.container){
34696 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
34698 this.checked = state;
34699 if(suppressEvent !== true){
34700 this.fireEvent("checkchange", this, state);
34706 handleClick : function(e){
34707 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
34708 this.setChecked(!this.checked);
34710 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
34714 * Ext JS Library 1.1.1
34715 * Copyright(c) 2006-2007, Ext JS, LLC.
34717 * Originally Released Under LGPL - original licence link has changed is not relivant.
34720 * <script type="text/javascript">
34724 * @class Roo.menu.DateItem
34725 * @extends Roo.menu.Adapter
34726 * A menu item that wraps the {@link Roo.DatPicker} component.
34728 * Creates a new DateItem
34729 * @param {Object} config Configuration options
34731 Roo.menu.DateItem = function(config){
34732 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
34733 /** The Roo.DatePicker object @type Roo.DatePicker */
34734 this.picker = this.component;
34735 this.addEvents({select: true});
34737 this.picker.on("render", function(picker){
34738 picker.getEl().swallowEvent("click");
34739 picker.container.addClass("x-menu-date-item");
34742 this.picker.on("select", this.onSelect, this);
34745 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
34747 onSelect : function(picker, date){
34748 this.fireEvent("select", this, date, picker);
34749 Roo.menu.DateItem.superclass.handleClick.call(this);
34753 * Ext JS Library 1.1.1
34754 * Copyright(c) 2006-2007, Ext JS, LLC.
34756 * Originally Released Under LGPL - original licence link has changed is not relivant.
34759 * <script type="text/javascript">
34763 * @class Roo.menu.ColorItem
34764 * @extends Roo.menu.Adapter
34765 * A menu item that wraps the {@link Roo.ColorPalette} component.
34767 * Creates a new ColorItem
34768 * @param {Object} config Configuration options
34770 Roo.menu.ColorItem = function(config){
34771 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
34772 /** The Roo.ColorPalette object @type Roo.ColorPalette */
34773 this.palette = this.component;
34774 this.relayEvents(this.palette, ["select"]);
34775 if(this.selectHandler){
34776 this.on('select', this.selectHandler, this.scope);
34779 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
34781 * Ext JS Library 1.1.1
34782 * Copyright(c) 2006-2007, Ext JS, LLC.
34784 * Originally Released Under LGPL - original licence link has changed is not relivant.
34787 * <script type="text/javascript">
34792 * @class Roo.menu.DateMenu
34793 * @extends Roo.menu.Menu
34794 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
34796 * Creates a new DateMenu
34797 * @param {Object} config Configuration options
34799 Roo.menu.DateMenu = function(config){
34800 Roo.menu.DateMenu.superclass.constructor.call(this, config);
34802 var di = new Roo.menu.DateItem(config);
34805 * The {@link Roo.DatePicker} instance for this DateMenu
34808 this.picker = di.picker;
34811 * @param {DatePicker} picker
34812 * @param {Date} date
34814 this.relayEvents(di, ["select"]);
34816 this.on('beforeshow', function(){
34818 this.picker.hideMonthPicker(true);
34822 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
34826 * Ext JS Library 1.1.1
34827 * Copyright(c) 2006-2007, Ext JS, LLC.
34829 * Originally Released Under LGPL - original licence link has changed is not relivant.
34832 * <script type="text/javascript">
34837 * @class Roo.menu.ColorMenu
34838 * @extends Roo.menu.Menu
34839 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
34841 * Creates a new ColorMenu
34842 * @param {Object} config Configuration options
34844 Roo.menu.ColorMenu = function(config){
34845 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
34847 var ci = new Roo.menu.ColorItem(config);
34850 * The {@link Roo.ColorPalette} instance for this ColorMenu
34851 * @type ColorPalette
34853 this.palette = ci.palette;
34856 * @param {ColorPalette} palette
34857 * @param {String} color
34859 this.relayEvents(ci, ["select"]);
34861 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
34863 * Ext JS Library 1.1.1
34864 * Copyright(c) 2006-2007, Ext JS, LLC.
34866 * Originally Released Under LGPL - original licence link has changed is not relivant.
34869 * <script type="text/javascript">
34873 * @class Roo.form.Field
34874 * @extends Roo.BoxComponent
34875 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
34877 * Creates a new Field
34878 * @param {Object} config Configuration options
34880 Roo.form.Field = function(config){
34881 Roo.form.Field.superclass.constructor.call(this, config);
34884 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
34886 * @cfg {String} fieldLabel Label to use when rendering a form.
34889 * @cfg {String} qtip Mouse over tip
34893 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
34895 invalidClass : "x-form-invalid",
34897 * @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")
34899 invalidText : "The value in this field is invalid",
34901 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
34903 focusClass : "x-form-focus",
34905 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
34906 automatic validation (defaults to "keyup").
34908 validationEvent : "keyup",
34910 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
34912 validateOnBlur : true,
34914 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
34916 validationDelay : 250,
34918 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
34919 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
34921 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
34923 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
34925 fieldClass : "x-form-field",
34927 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
34930 ----------- ----------------------------------------------------------------------
34931 qtip Display a quick tip when the user hovers over the field
34932 title Display a default browser title attribute popup
34933 under Add a block div beneath the field containing the error text
34934 side Add an error icon to the right of the field with a popup on hover
34935 [element id] Add the error text directly to the innerHTML of the specified element
34938 msgTarget : 'qtip',
34940 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
34945 * @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.
34950 * @cfg {Boolean} disabled True to disable the field (defaults to false).
34955 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
34957 inputType : undefined,
34960 * @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).
34962 tabIndex : undefined,
34965 isFormField : true,
34970 * @property {Roo.Element} fieldEl
34971 * Element Containing the rendered Field (with label etc.)
34974 * @cfg {Mixed} value A value to initialize this field with.
34979 * @cfg {String} name The field's HTML name attribute.
34982 * @cfg {String} cls A CSS class to apply to the field's underlying element.
34986 initComponent : function(){
34987 Roo.form.Field.superclass.initComponent.call(this);
34991 * Fires when this field receives input focus.
34992 * @param {Roo.form.Field} this
34997 * Fires when this field loses input focus.
34998 * @param {Roo.form.Field} this
35002 * @event specialkey
35003 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35004 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35005 * @param {Roo.form.Field} this
35006 * @param {Roo.EventObject} e The event object
35011 * Fires just before the field blurs if the field value has changed.
35012 * @param {Roo.form.Field} this
35013 * @param {Mixed} newValue The new value
35014 * @param {Mixed} oldValue The original value
35019 * Fires after the field has been marked as invalid.
35020 * @param {Roo.form.Field} this
35021 * @param {String} msg The validation message
35026 * Fires after the field has been validated with no errors.
35027 * @param {Roo.form.Field} this
35034 * Returns the name attribute of the field if available
35035 * @return {String} name The field name
35037 getName: function(){
35038 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35042 onRender : function(ct, position){
35043 Roo.form.Field.superclass.onRender.call(this, ct, position);
35045 var cfg = this.getAutoCreate();
35047 cfg.name = this.name || this.id;
35049 if(this.inputType){
35050 cfg.type = this.inputType;
35052 this.el = ct.createChild(cfg, position);
35054 var type = this.el.dom.type;
35056 if(type == 'password'){
35059 this.el.addClass('x-form-'+type);
35062 this.el.dom.readOnly = true;
35064 if(this.tabIndex !== undefined){
35065 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35068 this.el.addClass([this.fieldClass, this.cls]);
35073 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35074 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35075 * @return {Roo.form.Field} this
35077 applyTo : function(target){
35078 this.allowDomMove = false;
35079 this.el = Roo.get(target);
35080 this.render(this.el.dom.parentNode);
35085 initValue : function(){
35086 if(this.value !== undefined){
35087 this.setValue(this.value);
35088 }else if(this.el.dom.value.length > 0){
35089 this.setValue(this.el.dom.value);
35094 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35096 isDirty : function() {
35097 if(this.disabled) {
35100 return String(this.getValue()) !== String(this.originalValue);
35104 afterRender : function(){
35105 Roo.form.Field.superclass.afterRender.call(this);
35110 fireKey : function(e){
35111 if(e.isNavKeyPress()){
35112 this.fireEvent("specialkey", this, e);
35117 * Resets the current field value to the originally loaded value and clears any validation messages
35119 reset : function(){
35120 this.setValue(this.originalValue);
35121 this.clearInvalid();
35125 initEvents : function(){
35126 this.el.on(Roo.isIE ? "keydown" : "keypress", this.fireKey, this);
35127 this.el.on("focus", this.onFocus, this);
35128 this.el.on("blur", this.onBlur, this);
35130 // reference to original value for reset
35131 this.originalValue = this.getValue();
35135 onFocus : function(){
35136 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35137 this.el.addClass(this.focusClass);
35139 if(!this.hasFocus){
35140 this.hasFocus = true;
35141 this.startValue = this.getValue();
35142 this.fireEvent("focus", this);
35146 beforeBlur : Roo.emptyFn,
35149 onBlur : function(){
35151 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35152 this.el.removeClass(this.focusClass);
35154 this.hasFocus = false;
35155 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35158 var v = this.getValue();
35159 if(String(v) !== String(this.startValue)){
35160 this.fireEvent('change', this, v, this.startValue);
35162 this.fireEvent("blur", this);
35166 * Returns whether or not the field value is currently valid
35167 * @param {Boolean} preventMark True to disable marking the field invalid
35168 * @return {Boolean} True if the value is valid, else false
35170 isValid : function(preventMark){
35174 var restore = this.preventMark;
35175 this.preventMark = preventMark === true;
35176 var v = this.validateValue(this.processValue(this.getRawValue()));
35177 this.preventMark = restore;
35182 * Validates the field value
35183 * @return {Boolean} True if the value is valid, else false
35185 validate : function(){
35186 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35187 this.clearInvalid();
35193 processValue : function(value){
35198 // Subclasses should provide the validation implementation by overriding this
35199 validateValue : function(value){
35204 * Mark this field as invalid
35205 * @param {String} msg The validation message
35207 markInvalid : function(msg){
35208 if(!this.rendered || this.preventMark){ // not rendered
35211 this.el.addClass(this.invalidClass);
35212 msg = msg || this.invalidText;
35213 switch(this.msgTarget){
35215 this.el.dom.qtip = msg;
35216 this.el.dom.qclass = 'x-form-invalid-tip';
35217 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35218 Roo.QuickTips.enable();
35222 this.el.dom.title = msg;
35226 var elp = this.el.findParent('.x-form-element', 5, true);
35227 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35228 this.errorEl.setWidth(elp.getWidth(true)-20);
35230 this.errorEl.update(msg);
35231 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35234 if(!this.errorIcon){
35235 var elp = this.el.findParent('.x-form-element', 5, true);
35236 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35238 this.alignErrorIcon();
35239 this.errorIcon.dom.qtip = msg;
35240 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35241 this.errorIcon.show();
35242 this.on('resize', this.alignErrorIcon, this);
35245 var t = Roo.getDom(this.msgTarget);
35247 t.style.display = this.msgDisplay;
35250 this.fireEvent('invalid', this, msg);
35254 alignErrorIcon : function(){
35255 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35259 * Clear any invalid styles/messages for this field
35261 clearInvalid : function(){
35262 if(!this.rendered || this.preventMark){ // not rendered
35265 this.el.removeClass(this.invalidClass);
35266 switch(this.msgTarget){
35268 this.el.dom.qtip = '';
35271 this.el.dom.title = '';
35275 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35279 if(this.errorIcon){
35280 this.errorIcon.dom.qtip = '';
35281 this.errorIcon.hide();
35282 this.un('resize', this.alignErrorIcon, this);
35286 var t = Roo.getDom(this.msgTarget);
35288 t.style.display = 'none';
35291 this.fireEvent('valid', this);
35295 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35296 * @return {Mixed} value The field value
35298 getRawValue : function(){
35299 var v = this.el.getValue();
35300 if(v === this.emptyText){
35307 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35308 * @return {Mixed} value The field value
35310 getValue : function(){
35311 var v = this.el.getValue();
35312 if(v === this.emptyText || v === undefined){
35319 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35320 * @param {Mixed} value The value to set
35322 setRawValue : function(v){
35323 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35327 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35328 * @param {Mixed} value The value to set
35330 setValue : function(v){
35333 this.el.dom.value = (v === null || v === undefined ? '' : v);
35338 adjustSize : function(w, h){
35339 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35340 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35344 adjustWidth : function(tag, w){
35345 tag = tag.toLowerCase();
35346 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35347 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35348 if(tag == 'input'){
35351 if(tag = 'textarea'){
35354 }else if(Roo.isOpera){
35355 if(tag == 'input'){
35358 if(tag = 'textarea'){
35368 // anything other than normal should be considered experimental
35369 Roo.form.Field.msgFx = {
35371 show: function(msgEl, f){
35372 msgEl.setDisplayed('block');
35375 hide : function(msgEl, f){
35376 msgEl.setDisplayed(false).update('');
35381 show: function(msgEl, f){
35382 msgEl.slideIn('t', {stopFx:true});
35385 hide : function(msgEl, f){
35386 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35391 show: function(msgEl, f){
35392 msgEl.fixDisplay();
35393 msgEl.alignTo(f.el, 'tl-tr');
35394 msgEl.slideIn('l', {stopFx:true});
35397 hide : function(msgEl, f){
35398 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35403 * Ext JS Library 1.1.1
35404 * Copyright(c) 2006-2007, Ext JS, LLC.
35406 * Originally Released Under LGPL - original licence link has changed is not relivant.
35409 * <script type="text/javascript">
35414 * @class Roo.form.TextField
35415 * @extends Roo.form.Field
35416 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35417 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35419 * Creates a new TextField
35420 * @param {Object} config Configuration options
35422 Roo.form.TextField = function(config){
35423 Roo.form.TextField.superclass.constructor.call(this, config);
35427 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35428 * according to the default logic, but this event provides a hook for the developer to apply additional
35429 * logic at runtime to resize the field if needed.
35430 * @param {Roo.form.Field} this This text field
35431 * @param {Number} width The new field width
35437 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35439 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35443 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35447 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35451 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35455 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35459 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35461 disableKeyFilter : false,
35463 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35467 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35471 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35473 maxLength : Number.MAX_VALUE,
35475 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35477 minLengthText : "The minimum length for this field is {0}",
35479 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35481 maxLengthText : "The maximum length for this field is {0}",
35483 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35485 selectOnFocus : false,
35487 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35489 blankText : "This field is required",
35491 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35492 * If available, this function will be called only after the basic validators all return true, and will be passed the
35493 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35497 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35498 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35499 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35503 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35507 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35511 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35512 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35514 emptyClass : 'x-form-empty-field',
35517 initEvents : function(){
35518 Roo.form.TextField.superclass.initEvents.call(this);
35519 if(this.validationEvent == 'keyup'){
35520 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35521 this.el.on('keyup', this.filterValidation, this);
35523 else if(this.validationEvent !== false){
35524 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35526 if(this.selectOnFocus || this.emptyText){
35527 this.on("focus", this.preFocus, this);
35528 if(this.emptyText){
35529 this.on('blur', this.postBlur, this);
35530 this.applyEmptyText();
35533 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35534 this.el.on("keypress", this.filterKeys, this);
35537 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35538 this.el.on("click", this.autoSize, this);
35542 processValue : function(value){
35543 if(this.stripCharsRe){
35544 var newValue = value.replace(this.stripCharsRe, '');
35545 if(newValue !== value){
35546 this.setRawValue(newValue);
35553 filterValidation : function(e){
35554 if(!e.isNavKeyPress()){
35555 this.validationTask.delay(this.validationDelay);
35560 onKeyUp : function(e){
35561 if(!e.isNavKeyPress()){
35567 * Resets the current field value to the originally-loaded value and clears any validation messages.
35568 * Also adds emptyText and emptyClass if the original value was blank.
35570 reset : function(){
35571 Roo.form.TextField.superclass.reset.call(this);
35572 this.applyEmptyText();
35575 applyEmptyText : function(){
35576 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35577 this.setRawValue(this.emptyText);
35578 this.el.addClass(this.emptyClass);
35583 preFocus : function(){
35584 if(this.emptyText){
35585 if(this.el.dom.value == this.emptyText){
35586 this.setRawValue('');
35588 this.el.removeClass(this.emptyClass);
35590 if(this.selectOnFocus){
35591 this.el.dom.select();
35596 postBlur : function(){
35597 this.applyEmptyText();
35601 filterKeys : function(e){
35602 var k = e.getKey();
35603 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35606 var c = e.getCharCode(), cc = String.fromCharCode(c);
35607 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35610 if(!this.maskRe.test(cc)){
35615 setValue : function(v){
35616 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35617 this.el.removeClass(this.emptyClass);
35619 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35620 this.applyEmptyText();
35625 * Validates a value according to the field's validation rules and marks the field as invalid
35626 * if the validation fails
35627 * @param {Mixed} value The value to validate
35628 * @return {Boolean} True if the value is valid, else false
35630 validateValue : function(value){
35631 if(value.length < 1 || value === this.emptyText){ // if it's blank
35632 if(this.allowBlank){
35633 this.clearInvalid();
35636 this.markInvalid(this.blankText);
35640 if(value.length < this.minLength){
35641 this.markInvalid(String.format(this.minLengthText, this.minLength));
35644 if(value.length > this.maxLength){
35645 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35649 var vt = Roo.form.VTypes;
35650 if(!vt[this.vtype](value, this)){
35651 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35655 if(typeof this.validator == "function"){
35656 var msg = this.validator(value);
35658 this.markInvalid(msg);
35662 if(this.regex && !this.regex.test(value)){
35663 this.markInvalid(this.regexText);
35670 * Selects text in this field
35671 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35672 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35674 selectText : function(start, end){
35675 var v = this.getRawValue();
35677 start = start === undefined ? 0 : start;
35678 end = end === undefined ? v.length : end;
35679 var d = this.el.dom;
35680 if(d.setSelectionRange){
35681 d.setSelectionRange(start, end);
35682 }else if(d.createTextRange){
35683 var range = d.createTextRange();
35684 range.moveStart("character", start);
35685 range.moveEnd("character", v.length-end);
35692 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
35693 * This only takes effect if grow = true, and fires the autosize event.
35695 autoSize : function(){
35696 if(!this.grow || !this.rendered){
35700 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
35703 var v = el.dom.value;
35704 var d = document.createElement('div');
35705 d.appendChild(document.createTextNode(v));
35709 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
35710 this.el.setWidth(w);
35711 this.fireEvent("autosize", this, w);
35715 * Ext JS Library 1.1.1
35716 * Copyright(c) 2006-2007, Ext JS, LLC.
35718 * Originally Released Under LGPL - original licence link has changed is not relivant.
35721 * <script type="text/javascript">
35725 * @class Roo.form.Hidden
35726 * @extends Roo.form.TextField
35727 * Simple Hidden element used on forms
35729 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
35732 * Creates a new Hidden form element.
35733 * @param {Object} config Configuration options
35738 // easy hidden field...
35739 Roo.form.Hidden = function(config){
35740 Roo.form.Hidden.superclass.constructor.call(this, config);
35743 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
35745 inputType: 'hidden',
35748 labelSeparator: '',
35750 itemCls : 'x-form-item-display-none'
35758 * Ext JS Library 1.1.1
35759 * Copyright(c) 2006-2007, Ext JS, LLC.
35761 * Originally Released Under LGPL - original licence link has changed is not relivant.
35764 * <script type="text/javascript">
35768 * @class Roo.form.TriggerField
35769 * @extends Roo.form.TextField
35770 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
35771 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
35772 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
35773 * for which you can provide a custom implementation. For example:
35775 var trigger = new Roo.form.TriggerField();
35776 trigger.onTriggerClick = myTriggerFn;
35777 trigger.applyTo('my-field');
35780 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
35781 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
35782 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
35783 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
35785 * Create a new TriggerField.
35786 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
35787 * to the base TextField)
35789 Roo.form.TriggerField = function(config){
35790 this.mimicing = false;
35791 Roo.form.TriggerField.superclass.constructor.call(this, config);
35794 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
35796 * @cfg {String} triggerClass A CSS class to apply to the trigger
35799 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35800 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
35802 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
35804 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
35808 /** @cfg {Boolean} grow @hide */
35809 /** @cfg {Number} growMin @hide */
35810 /** @cfg {Number} growMax @hide */
35816 autoSize: Roo.emptyFn,
35820 deferHeight : true,
35823 actionMode : 'wrap',
35825 onResize : function(w, h){
35826 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
35827 if(typeof w == 'number'){
35828 this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));
35833 adjustSize : Roo.BoxComponent.prototype.adjustSize,
35836 getResizeEl : function(){
35841 getPositionEl : function(){
35846 alignErrorIcon : function(){
35847 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
35851 onRender : function(ct, position){
35852 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
35853 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
35854 this.trigger = this.wrap.createChild(this.triggerConfig ||
35855 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
35856 if(this.hideTrigger){
35857 this.trigger.setDisplayed(false);
35859 this.initTrigger();
35861 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
35866 initTrigger : function(){
35867 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
35868 this.trigger.addClassOnOver('x-form-trigger-over');
35869 this.trigger.addClassOnClick('x-form-trigger-click');
35873 onDestroy : function(){
35875 this.trigger.removeAllListeners();
35876 this.trigger.remove();
35879 this.wrap.remove();
35881 Roo.form.TriggerField.superclass.onDestroy.call(this);
35885 onFocus : function(){
35886 Roo.form.TriggerField.superclass.onFocus.call(this);
35887 if(!this.mimicing){
35888 this.wrap.addClass('x-trigger-wrap-focus');
35889 this.mimicing = true;
35890 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
35891 if(this.monitorTab){
35892 this.el.on("keydown", this.checkTab, this);
35898 checkTab : function(e){
35899 if(e.getKey() == e.TAB){
35900 this.triggerBlur();
35905 onBlur : function(){
35910 mimicBlur : function(e, t){
35911 if(!this.wrap.contains(t) && this.validateBlur()){
35912 this.triggerBlur();
35917 triggerBlur : function(){
35918 this.mimicing = false;
35919 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
35920 if(this.monitorTab){
35921 this.el.un("keydown", this.checkTab, this);
35923 this.wrap.removeClass('x-trigger-wrap-focus');
35924 Roo.form.TriggerField.superclass.onBlur.call(this);
35928 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
35929 validateBlur : function(e, t){
35934 onDisable : function(){
35935 Roo.form.TriggerField.superclass.onDisable.call(this);
35937 this.wrap.addClass('x-item-disabled');
35942 onEnable : function(){
35943 Roo.form.TriggerField.superclass.onEnable.call(this);
35945 this.wrap.removeClass('x-item-disabled');
35950 onShow : function(){
35951 var ae = this.getActionEl();
35954 ae.dom.style.display = '';
35955 ae.dom.style.visibility = 'visible';
35961 onHide : function(){
35962 var ae = this.getActionEl();
35963 ae.dom.style.display = 'none';
35967 * The function that should handle the trigger's click event. This method does nothing by default until overridden
35968 * by an implementing function.
35970 * @param {EventObject} e
35972 onTriggerClick : Roo.emptyFn
35975 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
35976 // to be extended by an implementing class. For an example of implementing this class, see the custom
35977 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
35978 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
35979 initComponent : function(){
35980 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
35982 this.triggerConfig = {
35983 tag:'span', cls:'x-form-twin-triggers', cn:[
35984 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
35985 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
35989 getTrigger : function(index){
35990 return this.triggers[index];
35993 initTrigger : function(){
35994 var ts = this.trigger.select('.x-form-trigger', true);
35995 this.wrap.setStyle('overflow', 'hidden');
35996 var triggerField = this;
35997 ts.each(function(t, all, index){
35998 t.hide = function(){
35999 var w = triggerField.wrap.getWidth();
36000 this.dom.style.display = 'none';
36001 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36003 t.show = function(){
36004 var w = triggerField.wrap.getWidth();
36005 this.dom.style.display = '';
36006 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36008 var triggerIndex = 'Trigger'+(index+1);
36010 if(this['hide'+triggerIndex]){
36011 t.dom.style.display = 'none';
36013 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36014 t.addClassOnOver('x-form-trigger-over');
36015 t.addClassOnClick('x-form-trigger-click');
36017 this.triggers = ts.elements;
36020 onTrigger1Click : Roo.emptyFn,
36021 onTrigger2Click : Roo.emptyFn
36024 * Ext JS Library 1.1.1
36025 * Copyright(c) 2006-2007, Ext JS, LLC.
36027 * Originally Released Under LGPL - original licence link has changed is not relivant.
36030 * <script type="text/javascript">
36034 * @class Roo.form.TextArea
36035 * @extends Roo.form.TextField
36036 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36037 * support for auto-sizing.
36039 * Creates a new TextArea
36040 * @param {Object} config Configuration options
36042 Roo.form.TextArea = function(config){
36043 Roo.form.TextArea.superclass.constructor.call(this, config);
36044 // these are provided exchanges for backwards compat
36045 // minHeight/maxHeight were replaced by growMin/growMax to be
36046 // compatible with TextField growing config values
36047 if(this.minHeight !== undefined){
36048 this.growMin = this.minHeight;
36050 if(this.maxHeight !== undefined){
36051 this.growMax = this.maxHeight;
36055 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36057 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36061 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36065 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36066 * in the field (equivalent to setting overflow: hidden, defaults to false)
36068 preventScrollbars: false,
36070 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36071 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36075 onRender : function(ct, position){
36077 this.defaultAutoCreate = {
36079 style:"width:300px;height:60px;",
36080 autocomplete: "off"
36083 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36085 this.textSizeEl = Roo.DomHelper.append(document.body, {
36086 tag: "pre", cls: "x-form-grow-sizer"
36088 if(this.preventScrollbars){
36089 this.el.setStyle("overflow", "hidden");
36091 this.el.setHeight(this.growMin);
36095 onDestroy : function(){
36096 if(this.textSizeEl){
36097 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36099 Roo.form.TextArea.superclass.onDestroy.call(this);
36103 onKeyUp : function(e){
36104 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36110 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36111 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36113 autoSize : function(){
36114 if(!this.grow || !this.textSizeEl){
36118 var v = el.dom.value;
36119 var ts = this.textSizeEl;
36122 ts.appendChild(document.createTextNode(v));
36125 Roo.fly(ts).setWidth(this.el.getWidth());
36127 v = "  ";
36130 v = v.replace(/\n/g, '<p> </p>');
36132 v += " \n ";
36135 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36136 if(h != this.lastHeight){
36137 this.lastHeight = h;
36138 this.el.setHeight(h);
36139 this.fireEvent("autosize", this, h);
36144 * Ext JS Library 1.1.1
36145 * Copyright(c) 2006-2007, Ext JS, LLC.
36147 * Originally Released Under LGPL - original licence link has changed is not relivant.
36150 * <script type="text/javascript">
36155 * @class Roo.form.NumberField
36156 * @extends Roo.form.TextField
36157 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36159 * Creates a new NumberField
36160 * @param {Object} config Configuration options
36162 Roo.form.NumberField = function(config){
36163 Roo.form.NumberField.superclass.constructor.call(this, config);
36166 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36168 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36170 fieldClass: "x-form-field x-form-num-field",
36172 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36174 allowDecimals : true,
36176 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36178 decimalSeparator : ".",
36180 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36182 decimalPrecision : 2,
36184 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36186 allowNegative : true,
36188 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36190 minValue : Number.NEGATIVE_INFINITY,
36192 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36194 maxValue : Number.MAX_VALUE,
36196 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36198 minText : "The minimum value for this field is {0}",
36200 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36202 maxText : "The maximum value for this field is {0}",
36204 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36205 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36207 nanText : "{0} is not a valid number",
36210 initEvents : function(){
36211 Roo.form.NumberField.superclass.initEvents.call(this);
36212 var allowed = "0123456789";
36213 if(this.allowDecimals){
36214 allowed += this.decimalSeparator;
36216 if(this.allowNegative){
36219 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36220 var keyPress = function(e){
36221 var k = e.getKey();
36222 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36225 var c = e.getCharCode();
36226 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36230 this.el.on("keypress", keyPress, this);
36234 validateValue : function(value){
36235 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36238 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36241 var num = this.parseValue(value);
36243 this.markInvalid(String.format(this.nanText, value));
36246 if(num < this.minValue){
36247 this.markInvalid(String.format(this.minText, this.minValue));
36250 if(num > this.maxValue){
36251 this.markInvalid(String.format(this.maxText, this.maxValue));
36257 getValue : function(){
36258 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36262 parseValue : function(value){
36263 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36264 return isNaN(value) ? '' : value;
36268 fixPrecision : function(value){
36269 var nan = isNaN(value);
36270 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36271 return nan ? '' : value;
36273 return parseFloat(value).toFixed(this.decimalPrecision);
36276 setValue : function(v){
36277 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36281 decimalPrecisionFcn : function(v){
36282 return Math.floor(v);
36285 beforeBlur : function(){
36286 var v = this.parseValue(this.getRawValue());
36288 this.setValue(this.fixPrecision(v));
36293 * Ext JS Library 1.1.1
36294 * Copyright(c) 2006-2007, Ext JS, LLC.
36296 * Originally Released Under LGPL - original licence link has changed is not relivant.
36299 * <script type="text/javascript">
36303 * @class Roo.form.DateField
36304 * @extends Roo.form.TriggerField
36305 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36307 * Create a new DateField
36308 * @param {Object} config
36310 Roo.form.DateField = function(config){
36311 Roo.form.DateField.superclass.constructor.call(this, config);
36317 * Fires when a date is selected
36318 * @param {Roo.form.DateField} combo This combo box
36319 * @param {Date} date The date selected
36326 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36327 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36328 this.ddMatch = null;
36329 if(this.disabledDates){
36330 var dd = this.disabledDates;
36332 for(var i = 0; i < dd.length; i++){
36334 if(i != dd.length-1) re += "|";
36336 this.ddMatch = new RegExp(re + ")");
36340 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36342 * @cfg {String} format
36343 * The default date format string which can be overriden for localization support. The format must be
36344 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36348 * @cfg {String} altFormats
36349 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36350 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36352 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36354 * @cfg {Array} disabledDays
36355 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36357 disabledDays : null,
36359 * @cfg {String} disabledDaysText
36360 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36362 disabledDaysText : "Disabled",
36364 * @cfg {Array} disabledDates
36365 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36366 * expression so they are very powerful. Some examples:
36368 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36369 * <li>["03/08", "09/16"] would disable those days for every year</li>
36370 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36371 * <li>["03/../2006"] would disable every day in March 2006</li>
36372 * <li>["^03"] would disable every day in every March</li>
36374 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36375 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36377 disabledDates : null,
36379 * @cfg {String} disabledDatesText
36380 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36382 disabledDatesText : "Disabled",
36384 * @cfg {Date/String} minValue
36385 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36386 * valid format (defaults to null).
36390 * @cfg {Date/String} maxValue
36391 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36392 * valid format (defaults to null).
36396 * @cfg {String} minText
36397 * The error text to display when the date in the cell is before minValue (defaults to
36398 * 'The date in this field must be after {minValue}').
36400 minText : "The date in this field must be equal to or after {0}",
36402 * @cfg {String} maxText
36403 * The error text to display when the date in the cell is after maxValue (defaults to
36404 * 'The date in this field must be before {maxValue}').
36406 maxText : "The date in this field must be equal to or before {0}",
36408 * @cfg {String} invalidText
36409 * The error text to display when the date in the field is invalid (defaults to
36410 * '{value} is not a valid date - it must be in the format {format}').
36412 invalidText : "{0} is not a valid date - it must be in the format {1}",
36414 * @cfg {String} triggerClass
36415 * An additional CSS class used to style the trigger button. The trigger will always get the
36416 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36417 * which displays a calendar icon).
36419 triggerClass : 'x-form-date-trigger',
36423 * @cfg {bool} useIso
36424 * if enabled, then the date field will use a hidden field to store the
36425 * real value as iso formated date. default (false)
36429 * @cfg {String/Object} autoCreate
36430 * A DomHelper element spec, or true for a default element spec (defaults to
36431 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36434 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36437 hiddenField: false,
36439 onRender : function(ct, position)
36441 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36443 this.el.dom.removeAttribute('name');
36444 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36446 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36447 // prevent input submission
36448 this.hiddenName = this.name;
36455 validateValue : function(value)
36457 value = this.formatDate(value);
36458 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36461 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36464 var svalue = value;
36465 value = this.parseDate(value);
36467 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36470 var time = value.getTime();
36471 if(this.minValue && time < this.minValue.getTime()){
36472 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36475 if(this.maxValue && time > this.maxValue.getTime()){
36476 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36479 if(this.disabledDays){
36480 var day = value.getDay();
36481 for(var i = 0; i < this.disabledDays.length; i++) {
36482 if(day === this.disabledDays[i]){
36483 this.markInvalid(this.disabledDaysText);
36488 var fvalue = this.formatDate(value);
36489 if(this.ddMatch && this.ddMatch.test(fvalue)){
36490 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36497 // Provides logic to override the default TriggerField.validateBlur which just returns true
36498 validateBlur : function(){
36499 return !this.menu || !this.menu.isVisible();
36503 * Returns the current date value of the date field.
36504 * @return {Date} The date value
36506 getValue : function(){
36508 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36512 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36513 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36514 * (the default format used is "m/d/y").
36517 //All of these calls set the same date value (May 4, 2006)
36519 //Pass a date object:
36520 var dt = new Date('5/4/06');
36521 dateField.setValue(dt);
36523 //Pass a date string (default format):
36524 dateField.setValue('5/4/06');
36526 //Pass a date string (custom format):
36527 dateField.format = 'Y-m-d';
36528 dateField.setValue('2006-5-4');
36530 * @param {String/Date} date The date or valid date string
36532 setValue : function(date){
36533 if (this.hiddenField) {
36534 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36536 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36540 parseDate : function(value){
36541 if(!value || value instanceof Date){
36544 var v = Date.parseDate(value, this.format);
36545 if(!v && this.altFormats){
36546 if(!this.altFormatsArray){
36547 this.altFormatsArray = this.altFormats.split("|");
36549 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36550 v = Date.parseDate(value, this.altFormatsArray[i]);
36557 formatDate : function(date, fmt){
36558 return (!date || !(date instanceof Date)) ?
36559 date : date.dateFormat(fmt || this.format);
36564 select: function(m, d){
36566 this.fireEvent('select', this, d);
36568 show : function(){ // retain focus styling
36572 this.focus.defer(10, this);
36573 var ml = this.menuListeners;
36574 this.menu.un("select", ml.select, this);
36575 this.menu.un("show", ml.show, this);
36576 this.menu.un("hide", ml.hide, this);
36581 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36582 onTriggerClick : function(){
36586 if(this.menu == null){
36587 this.menu = new Roo.menu.DateMenu();
36589 Roo.apply(this.menu.picker, {
36590 showClear: this.allowBlank,
36591 minDate : this.minValue,
36592 maxDate : this.maxValue,
36593 disabledDatesRE : this.ddMatch,
36594 disabledDatesText : this.disabledDatesText,
36595 disabledDays : this.disabledDays,
36596 disabledDaysText : this.disabledDaysText,
36597 format : this.format,
36598 minText : String.format(this.minText, this.formatDate(this.minValue)),
36599 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36601 this.menu.on(Roo.apply({}, this.menuListeners, {
36604 this.menu.picker.setValue(this.getValue() || new Date());
36605 this.menu.show(this.el, "tl-bl?");
36608 beforeBlur : function(){
36609 var v = this.parseDate(this.getRawValue());
36615 /** @cfg {Boolean} grow @hide */
36616 /** @cfg {Number} growMin @hide */
36617 /** @cfg {Number} growMax @hide */
36624 * Ext JS Library 1.1.1
36625 * Copyright(c) 2006-2007, Ext JS, LLC.
36627 * Originally Released Under LGPL - original licence link has changed is not relivant.
36630 * <script type="text/javascript">
36635 * @class Roo.form.ComboBox
36636 * @extends Roo.form.TriggerField
36637 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36639 * Create a new ComboBox.
36640 * @param {Object} config Configuration options
36642 Roo.form.ComboBox = function(config){
36643 Roo.form.ComboBox.superclass.constructor.call(this, config);
36647 * Fires when the dropdown list is expanded
36648 * @param {Roo.form.ComboBox} combo This combo box
36653 * Fires when the dropdown list is collapsed
36654 * @param {Roo.form.ComboBox} combo This combo box
36658 * @event beforeselect
36659 * Fires before a list item is selected. Return false to cancel the selection.
36660 * @param {Roo.form.ComboBox} combo This combo box
36661 * @param {Roo.data.Record} record The data record returned from the underlying store
36662 * @param {Number} index The index of the selected item in the dropdown list
36664 'beforeselect' : true,
36667 * Fires when a list item is selected
36668 * @param {Roo.form.ComboBox} combo This combo box
36669 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36670 * @param {Number} index The index of the selected item in the dropdown list
36674 * @event beforequery
36675 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36676 * The event object passed has these properties:
36677 * @param {Roo.form.ComboBox} combo This combo box
36678 * @param {String} query The query
36679 * @param {Boolean} forceAll true to force "all" query
36680 * @param {Boolean} cancel true to cancel the query
36681 * @param {Object} e The query event object
36683 'beforequery': true
36685 if(this.transform){
36686 this.allowDomMove = false;
36687 var s = Roo.getDom(this.transform);
36688 if(!this.hiddenName){
36689 this.hiddenName = s.name;
36692 this.mode = 'local';
36693 var d = [], opts = s.options;
36694 for(var i = 0, len = opts.length;i < len; i++){
36696 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
36698 this.value = value;
36700 d.push([value, o.text]);
36702 this.store = new Roo.data.SimpleStore({
36704 fields: ['value', 'text'],
36707 this.valueField = 'value';
36708 this.displayField = 'text';
36710 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
36711 if(!this.lazyRender){
36712 this.target = true;
36713 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
36714 s.parentNode.removeChild(s); // remove it
36715 this.render(this.el.parentNode);
36717 s.parentNode.removeChild(s); // remove it
36722 this.store = Roo.factory(this.store, Roo.data);
36725 this.selectedIndex = -1;
36726 if(this.mode == 'local'){
36727 if(config.queryDelay === undefined){
36728 this.queryDelay = 10;
36730 if(config.minChars === undefined){
36736 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
36738 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
36741 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
36742 * rendering into an Roo.Editor, defaults to false)
36745 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
36746 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
36749 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
36752 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
36753 * the dropdown list (defaults to undefined, with no header element)
36757 * @cfg {String/Roo.Template} tpl The template to use to render the output
36761 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
36763 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
36765 listWidth: undefined,
36767 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
36768 * mode = 'remote' or 'text' if mode = 'local')
36770 displayField: undefined,
36772 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
36773 * mode = 'remote' or 'value' if mode = 'local').
36774 * Note: use of a valueField requires the user make a selection
36775 * in order for a value to be mapped.
36777 valueField: undefined,
36779 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
36780 * field's data value (defaults to the underlying DOM element's name)
36782 hiddenName: undefined,
36784 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
36788 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
36790 selectedClass: 'x-combo-selected',
36792 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36793 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
36794 * which displays a downward arrow icon).
36796 triggerClass : 'x-form-arrow-trigger',
36798 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
36802 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
36803 * anchor positions (defaults to 'tl-bl')
36805 listAlign: 'tl-bl?',
36807 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
36811 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
36812 * query specified by the allQuery config option (defaults to 'query')
36814 triggerAction: 'query',
36816 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
36817 * (defaults to 4, does not apply if editable = false)
36821 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
36822 * delay (typeAheadDelay) if it matches a known value (defaults to false)
36826 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
36827 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
36831 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
36832 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
36836 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
36837 * when editable = true (defaults to false)
36839 selectOnFocus:false,
36841 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
36843 queryParam: 'query',
36845 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
36846 * when mode = 'remote' (defaults to 'Loading...')
36848 loadingText: 'Loading...',
36850 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
36854 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
36858 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
36859 * traditional select (defaults to true)
36863 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
36867 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
36871 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
36872 * listWidth has a higher value)
36876 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
36877 * allow the user to set arbitrary text into the field (defaults to false)
36879 forceSelection:false,
36881 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
36882 * if typeAhead = true (defaults to 250)
36884 typeAheadDelay : 250,
36886 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
36887 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
36889 valueNotFoundText : undefined,
36891 * @cfg {bool} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
36893 blockFocus : false,
36896 * @cfg {bool} disableClear Disable showing of clear button.
36898 disableClear : false,
36901 onRender : function(ct, position){
36902 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
36903 if(this.hiddenName){
36904 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
36906 this.hiddenField.value =
36907 this.hiddenValue !== undefined ? this.hiddenValue :
36908 this.value !== undefined ? this.value : '';
36910 // prevent input submission
36911 this.el.dom.removeAttribute('name');
36914 this.el.dom.setAttribute('autocomplete', 'off');
36917 var cls = 'x-combo-list';
36919 this.list = new Roo.Layer({
36920 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
36923 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
36924 this.list.setWidth(lw);
36925 this.list.swallowEvent('mousewheel');
36926 this.assetHeight = 0;
36929 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
36930 this.assetHeight += this.header.getHeight();
36933 this.innerList = this.list.createChild({cls:cls+'-inner'});
36934 this.innerList.on('mouseover', this.onViewOver, this);
36935 this.innerList.on('mousemove', this.onViewMove, this);
36936 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
36938 if(this.allowBlank && !this.pageSize && !this.disableClear){
36939 this.footer = this.list.createChild({cls:cls+'-ft'});
36940 this.pageTb = new Roo.Toolbar(this.footer);
36944 this.footer = this.list.createChild({cls:cls+'-ft'});
36945 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
36946 {pageSize: this.pageSize});
36950 if (this.pageTb && this.allowBlank && !this.disableClear) {
36952 this.pageTb.add(new Roo.Toolbar.Fill(), {
36953 cls: 'x-btn-icon x-btn-clear',
36955 handler: function()
36958 _this.clearValue();
36959 _this.onSelect(false, -1);
36964 this.assetHeight += this.footer.getHeight();
36969 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
36972 this.view = new Roo.View(this.innerList, this.tpl, {
36973 singleSelect:true, store: this.store, selectedClass: this.selectedClass
36976 this.view.on('click', this.onViewClick, this);
36978 this.store.on('beforeload', this.onBeforeLoad, this);
36979 this.store.on('load', this.onLoad, this);
36980 this.store.on('loadexception', this.collapse, this);
36982 if(this.resizable){
36983 this.resizer = new Roo.Resizable(this.list, {
36984 pinned:true, handles:'se'
36986 this.resizer.on('resize', function(r, w, h){
36987 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
36988 this.listWidth = w;
36989 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
36990 this.restrictHeight();
36992 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
36994 if(!this.editable){
36995 this.editable = true;
36996 this.setEditable(false);
37001 initEvents : function(){
37002 Roo.form.ComboBox.superclass.initEvents.call(this);
37004 this.keyNav = new Roo.KeyNav(this.el, {
37005 "up" : function(e){
37006 this.inKeyMode = true;
37010 "down" : function(e){
37011 if(!this.isExpanded()){
37012 this.onTriggerClick();
37014 this.inKeyMode = true;
37019 "enter" : function(e){
37020 this.onViewClick();
37024 "esc" : function(e){
37028 "tab" : function(e){
37029 this.onViewClick(false);
37035 doRelay : function(foo, bar, hname){
37036 if(hname == 'down' || this.scope.isExpanded()){
37037 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37044 this.queryDelay = Math.max(this.queryDelay || 10,
37045 this.mode == 'local' ? 10 : 250);
37046 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37047 if(this.typeAhead){
37048 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37050 if(this.editable !== false){
37051 this.el.on("keyup", this.onKeyUp, this);
37053 if(this.forceSelection){
37054 this.on('blur', this.doForce, this);
37058 onDestroy : function(){
37060 this.view.setStore(null);
37061 this.view.el.removeAllListeners();
37062 this.view.el.remove();
37063 this.view.purgeListeners();
37066 this.list.destroy();
37069 this.store.un('beforeload', this.onBeforeLoad, this);
37070 this.store.un('load', this.onLoad, this);
37071 this.store.un('loadexception', this.collapse, this);
37073 Roo.form.ComboBox.superclass.onDestroy.call(this);
37077 fireKey : function(e){
37078 if(e.isNavKeyPress() && !this.list.isVisible()){
37079 this.fireEvent("specialkey", this, e);
37084 onResize: function(w, h){
37085 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37086 if(this.list && this.listWidth === undefined){
37087 var lw = Math.max(w, this.minListWidth);
37088 this.list.setWidth(lw);
37089 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37094 * Allow or prevent the user from directly editing the field text. If false is passed,
37095 * the user will only be able to select from the items defined in the dropdown list. This method
37096 * is the runtime equivalent of setting the 'editable' config option at config time.
37097 * @param {Boolean} value True to allow the user to directly edit the field text
37099 setEditable : function(value){
37100 if(value == this.editable){
37103 this.editable = value;
37105 this.el.dom.setAttribute('readOnly', true);
37106 this.el.on('mousedown', this.onTriggerClick, this);
37107 this.el.addClass('x-combo-noedit');
37109 this.el.dom.setAttribute('readOnly', false);
37110 this.el.un('mousedown', this.onTriggerClick, this);
37111 this.el.removeClass('x-combo-noedit');
37116 onBeforeLoad : function(){
37117 if(!this.hasFocus){
37120 this.innerList.update(this.loadingText ?
37121 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37122 this.restrictHeight();
37123 this.selectedIndex = -1;
37127 onLoad : function(){
37128 if(!this.hasFocus){
37131 if(this.store.getCount() > 0){
37133 this.restrictHeight();
37134 if(this.lastQuery == this.allQuery){
37136 this.el.dom.select();
37138 if(!this.selectByValue(this.value, true)){
37139 this.select(0, true);
37143 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37144 this.taTask.delay(this.typeAheadDelay);
37148 this.onEmptyResults();
37154 onTypeAhead : function(){
37155 if(this.store.getCount() > 0){
37156 var r = this.store.getAt(0);
37157 var newValue = r.data[this.displayField];
37158 var len = newValue.length;
37159 var selStart = this.getRawValue().length;
37160 if(selStart != len){
37161 this.setRawValue(newValue);
37162 this.selectText(selStart, newValue.length);
37168 onSelect : function(record, index){
37169 if(this.fireEvent('beforeselect', this, record, index) !== false){
37170 this.setFromData(index > -1 ? record.data : false);
37172 this.fireEvent('select', this, record, index);
37177 * Returns the currently selected field value or empty string if no value is set.
37178 * @return {String} value The selected value
37180 getValue : function(){
37181 if(this.valueField){
37182 return typeof this.value != 'undefined' ? this.value : '';
37184 return Roo.form.ComboBox.superclass.getValue.call(this);
37189 * Clears any text/value currently set in the field
37191 clearValue : function(){
37192 if(this.hiddenField){
37193 this.hiddenField.value = '';
37196 this.setRawValue('');
37197 this.lastSelectionText = '';
37198 this.applyEmptyText();
37202 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37203 * will be displayed in the field. If the value does not match the data value of an existing item,
37204 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37205 * Otherwise the field will be blank (although the value will still be set).
37206 * @param {String} value The value to match
37208 setValue : function(v){
37210 if(this.valueField){
37211 var r = this.findRecord(this.valueField, v);
37213 text = r.data[this.displayField];
37214 }else if(this.valueNotFoundText !== undefined){
37215 text = this.valueNotFoundText;
37218 this.lastSelectionText = text;
37219 if(this.hiddenField){
37220 this.hiddenField.value = v;
37222 Roo.form.ComboBox.superclass.setValue.call(this, text);
37226 * @property {Object} the last set data for the element
37231 * Sets the value of the field based on a object which is related to the record format for the store.
37232 * @param {Object} value the value to set as. or false on reset?
37234 setFromData : function(o){
37235 var dv = ''; // display value
37236 var vv = ''; // value value..
37238 if (this.displayField) {
37239 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37241 // this is an error condition!!!
37242 console.log('no value field set for '+ this.name);
37245 if(this.valueField){
37246 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37248 if(this.hiddenField){
37249 this.hiddenField.value = vv;
37251 this.lastSelectionText = dv;
37252 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37256 // no hidden field.. - we store the value in 'value', but still display
37257 // display field!!!!
37258 this.lastSelectionText = dv;
37259 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37265 reset : function(){
37266 // overridden so that last data is reset..
37267 this.setValue(this.originalValue);
37268 this.clearInvalid();
37269 this.lastData = false;
37272 findRecord : function(prop, value){
37274 if(this.store.getCount() > 0){
37275 this.store.each(function(r){
37276 if(r.data[prop] == value){
37286 onViewMove : function(e, t){
37287 this.inKeyMode = false;
37291 onViewOver : function(e, t){
37292 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37295 var item = this.view.findItemFromChild(t);
37297 var index = this.view.indexOf(item);
37298 this.select(index, false);
37303 onViewClick : function(doFocus){
37304 var index = this.view.getSelectedIndexes()[0];
37305 var r = this.store.getAt(index);
37307 this.onSelect(r, index);
37309 if(doFocus !== false && !this.blockFocus){
37315 restrictHeight : function(){
37316 this.innerList.dom.style.height = '';
37317 var inner = this.innerList.dom;
37318 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37319 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37320 this.list.beginUpdate();
37321 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37322 this.list.alignTo(this.el, this.listAlign);
37323 this.list.endUpdate();
37327 onEmptyResults : function(){
37332 * Returns true if the dropdown list is expanded, else false.
37334 isExpanded : function(){
37335 return this.list.isVisible();
37339 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37340 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37341 * @param {String} value The data value of the item to select
37342 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37343 * selected item if it is not currently in view (defaults to true)
37344 * @return {Boolean} True if the value matched an item in the list, else false
37346 selectByValue : function(v, scrollIntoView){
37347 if(v !== undefined && v !== null){
37348 var r = this.findRecord(this.valueField || this.displayField, v);
37350 this.select(this.store.indexOf(r), scrollIntoView);
37358 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37359 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37360 * @param {Number} index The zero-based index of the list item to select
37361 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37362 * selected item if it is not currently in view (defaults to true)
37364 select : function(index, scrollIntoView){
37365 this.selectedIndex = index;
37366 this.view.select(index);
37367 if(scrollIntoView !== false){
37368 var el = this.view.getNode(index);
37370 this.innerList.scrollChildIntoView(el, false);
37376 selectNext : function(){
37377 var ct = this.store.getCount();
37379 if(this.selectedIndex == -1){
37381 }else if(this.selectedIndex < ct-1){
37382 this.select(this.selectedIndex+1);
37388 selectPrev : function(){
37389 var ct = this.store.getCount();
37391 if(this.selectedIndex == -1){
37393 }else if(this.selectedIndex != 0){
37394 this.select(this.selectedIndex-1);
37400 onKeyUp : function(e){
37401 if(this.editable !== false && !e.isSpecialKey()){
37402 this.lastKey = e.getKey();
37403 this.dqTask.delay(this.queryDelay);
37408 validateBlur : function(){
37409 return !this.list || !this.list.isVisible();
37413 initQuery : function(){
37414 this.doQuery(this.getRawValue());
37418 doForce : function(){
37419 if(this.el.dom.value.length > 0){
37420 this.el.dom.value =
37421 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37422 this.applyEmptyText();
37427 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37428 * query allowing the query action to be canceled if needed.
37429 * @param {String} query The SQL query to execute
37430 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37431 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37432 * saved in the current store (defaults to false)
37434 doQuery : function(q, forceAll){
37435 if(q === undefined || q === null){
37440 forceAll: forceAll,
37444 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37448 forceAll = qe.forceAll;
37449 if(forceAll === true || (q.length >= this.minChars)){
37450 if(this.lastQuery != q){
37451 this.lastQuery = q;
37452 if(this.mode == 'local'){
37453 this.selectedIndex = -1;
37455 this.store.clearFilter();
37457 this.store.filter(this.displayField, q);
37461 this.store.baseParams[this.queryParam] = q;
37463 params: this.getParams(q)
37468 this.selectedIndex = -1;
37475 getParams : function(q){
37477 //p[this.queryParam] = q;
37480 p.limit = this.pageSize;
37486 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37488 collapse : function(){
37489 if(!this.isExpanded()){
37493 Roo.get(document).un('mousedown', this.collapseIf, this);
37494 Roo.get(document).un('mousewheel', this.collapseIf, this);
37495 this.fireEvent('collapse', this);
37499 collapseIf : function(e){
37500 if(!e.within(this.wrap) && !e.within(this.list)){
37506 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37508 expand : function(){
37509 if(this.isExpanded() || !this.hasFocus){
37512 this.list.alignTo(this.el, this.listAlign);
37514 Roo.get(document).on('mousedown', this.collapseIf, this);
37515 Roo.get(document).on('mousewheel', this.collapseIf, this);
37516 this.fireEvent('expand', this);
37520 // Implements the default empty TriggerField.onTriggerClick function
37521 onTriggerClick : function(){
37525 if(this.isExpanded()){
37527 if (!this.blockFocus) {
37532 this.hasFocus = true;
37533 if(this.triggerAction == 'all') {
37534 this.doQuery(this.allQuery, true);
37536 this.doQuery(this.getRawValue());
37538 if (!this.blockFocus) {
37545 * @cfg {Boolean} grow
37549 * @cfg {Number} growMin
37553 * @cfg {Number} growMax
37562 * Ext JS Library 1.1.1
37563 * Copyright(c) 2006-2007, Ext JS, LLC.
37565 * Originally Released Under LGPL - original licence link has changed is not relivant.
37568 * <script type="text/javascript">
37571 * @class Roo.form.Checkbox
37572 * @extends Roo.form.Field
37573 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
37575 * Creates a new Checkbox
37576 * @param {Object} config Configuration options
37578 Roo.form.Checkbox = function(config){
37579 Roo.form.Checkbox.superclass.constructor.call(this, config);
37583 * Fires when the checkbox is checked or unchecked.
37584 * @param {Roo.form.Checkbox} this This checkbox
37585 * @param {Boolean} checked The new checked value
37591 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
37593 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
37595 focusClass : undefined,
37597 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
37599 fieldClass: "x-form-field",
37601 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
37605 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37606 * {tag: "input", type: "checkbox", autocomplete: "off"})
37608 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
37610 * @cfg {String} boxLabel The text that appears beside the checkbox
37614 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
37618 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
37620 valueOff: '0', // value when not checked..
37622 actionMode : 'viewEl',
37625 itemCls : 'x-menu-check-item x-form-item',
37626 groupClass : 'x-menu-group-item',
37627 inputType : 'hidden',
37630 inSetChecked: false, // check that we are not calling self...
37632 inputElement: false, // real input element?
37633 basedOn: false, // ????
37635 isFormField: true, // not sure where this is needed!!!!
37637 onResize : function(){
37638 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
37639 if(!this.boxLabel){
37640 this.el.alignTo(this.wrap, 'c-c');
37644 initEvents : function(){
37645 Roo.form.Checkbox.superclass.initEvents.call(this);
37646 this.el.on("click", this.onClick, this);
37647 this.el.on("change", this.onClick, this);
37651 getResizeEl : function(){
37655 getPositionEl : function(){
37660 onRender : function(ct, position){
37661 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
37663 if(this.inputValue !== undefined){
37664 this.el.dom.value = this.inputValue;
37667 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
37668 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
37669 var viewEl = this.wrap.createChild({
37670 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
37671 this.viewEl = viewEl;
37672 this.wrap.on('click', this.onClick, this);
37674 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
37675 this.el.on('propertychange', this.setFromHidden, this); //ie
37680 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
37681 // viewEl.on('click', this.onClick, this);
37683 //if(this.checked){
37684 this.setChecked(this.checked);
37686 //this.checked = this.el.dom;
37692 initValue : Roo.emptyFn,
37695 * Returns the checked state of the checkbox.
37696 * @return {Boolean} True if checked, else false
37698 getValue : function(){
37700 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
37702 return this.valueOff;
37707 onClick : function(){
37708 this.setChecked(!this.checked);
37710 //if(this.el.dom.checked != this.checked){
37711 // this.setValue(this.el.dom.checked);
37716 * Sets the checked state of the checkbox.
37717 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
37719 setValue : function(v,suppressEvent){
37720 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
37721 //if(this.el && this.el.dom){
37722 // this.el.dom.checked = this.checked;
37723 // this.el.dom.defaultChecked = this.checked;
37725 this.setChecked(v === this.inputValue);
37726 //this.fireEvent("check", this, this.checked);
37729 setChecked : function(state,suppressEvent)
37731 if (this.inSetChecked) {
37732 this.checked = state;
37738 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
37740 this.checked = state;
37741 if(suppressEvent !== true){
37742 this.fireEvent('checkchange', this, state);
37744 this.inSetChecked = true;
37745 this.el.dom.value = state ? this.inputValue : this.valueOff;
37746 this.inSetChecked = false;
37749 // handle setting of hidden value by some other method!!?!?
37750 setFromHidden: function()
37755 //console.log("SET FROM HIDDEN");
37756 //alert('setFrom hidden');
37757 this.setValue(this.el.dom.value);
37760 onDestroy : function()
37763 Roo.get(this.viewEl).remove();
37766 Roo.form.Checkbox.superclass.onDestroy.call(this);
37771 * Ext JS Library 1.1.1
37772 * Copyright(c) 2006-2007, Ext JS, LLC.
37774 * Originally Released Under LGPL - original licence link has changed is not relivant.
37777 * <script type="text/javascript">
37781 * @class Roo.form.Radio
37782 * @extends Roo.form.Checkbox
37783 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
37784 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
37786 * Creates a new Radio
37787 * @param {Object} config Configuration options
37789 Roo.form.Radio = function(){
37790 Roo.form.Radio.superclass.constructor.apply(this, arguments);
37792 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
37793 inputType: 'radio',
37796 * If this radio is part of a group, it will return the selected value
37799 getGroupValue : function(){
37800 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
37802 });//<script type="text/javascript">
37805 * Ext JS Library 1.1.1
37806 * Copyright(c) 2006-2007, Ext JS, LLC.
37807 * licensing@extjs.com
37809 * http://www.extjs.com/license
37815 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
37816 * - IE ? - no idea how much works there.
37824 * @class Ext.form.HtmlEditor
37825 * @extends Ext.form.Field
37826 * Provides a lightweight HTML Editor component.
37827 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
37829 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
37830 * supported by this editor.</b><br/><br/>
37831 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
37832 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
37834 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
37836 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
37840 * @cfg {String} createLinkText The default text for the create link prompt
37842 createLinkText : 'Please enter the URL for the link:',
37844 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
37846 defaultLinkValue : 'http:/'+'/',
37852 // private properties
37853 validationEvent : false,
37855 initialized : false,
37857 sourceEditMode : false,
37858 onFocus : Roo.emptyFn,
37860 hideMode:'offsets',
37861 defaultAutoCreate : {
37863 style:"width:500px;height:300px;",
37864 autocomplete: "off"
37868 initComponent : function(){
37871 * @event initialize
37872 * Fires when the editor is fully initialized (including the iframe)
37873 * @param {HtmlEditor} this
37878 * Fires when the editor is first receives the focus. Any insertion must wait
37879 * until after this event.
37880 * @param {HtmlEditor} this
37884 * @event beforesync
37885 * Fires before the textarea is updated with content from the editor iframe. Return false
37886 * to cancel the sync.
37887 * @param {HtmlEditor} this
37888 * @param {String} html
37892 * @event beforepush
37893 * Fires before the iframe editor is updated with content from the textarea. Return false
37894 * to cancel the push.
37895 * @param {HtmlEditor} this
37896 * @param {String} html
37901 * Fires when the textarea is updated with content from the editor iframe.
37902 * @param {HtmlEditor} this
37903 * @param {String} html
37908 * Fires when the iframe editor is updated with content from the textarea.
37909 * @param {HtmlEditor} this
37910 * @param {String} html
37914 * @event editmodechange
37915 * Fires when the editor switches edit modes
37916 * @param {HtmlEditor} this
37917 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
37919 editmodechange: true,
37921 * @event editorevent
37922 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
37923 * @param {HtmlEditor} this
37930 * Protected method that will not generally be called directly. It
37931 * is called when the editor creates its toolbar. Override this method if you need to
37932 * add custom toolbar buttons.
37933 * @param {HtmlEditor} editor
37935 createToolbar : function(editor){
37936 if (!editor.toolbars || !editor.toolbars.length) {
37937 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
37940 for (var i =0 ; i < editor.toolbars.length;i++) {
37941 editor.toolbars[i].init(editor);
37948 * Protected method that will not generally be called directly. It
37949 * is called when the editor initializes the iframe with HTML contents. Override this method if you
37950 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
37952 getDocMarkup : function(){
37953 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
37957 onRender : function(ct, position){
37958 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
37959 this.el.dom.style.border = '0 none';
37960 this.el.dom.setAttribute('tabIndex', -1);
37961 this.el.addClass('x-hidden');
37962 if(Roo.isIE){ // fix IE 1px bogus margin
37963 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
37965 this.wrap = this.el.wrap({
37966 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
37969 this.frameId = Roo.id();
37970 this.createToolbar(this);
37977 var iframe = this.wrap.createChild({
37980 name: this.frameId,
37981 frameBorder : 'no',
37982 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
37985 // console.log(iframe);
37986 //this.wrap.dom.appendChild(iframe);
37988 this.iframe = iframe.dom;
37990 this.assignDocWin();
37992 this.doc.designMode = 'on';
37995 this.doc.write(this.getDocMarkup());
37999 var task = { // must defer to wait for browser to be ready
38001 //console.log("run task?" + this.doc.readyState);
38002 this.assignDocWin();
38003 if(this.doc.body || this.doc.readyState == 'complete'){
38007 this.doc.designMode="on";
38011 Roo.TaskMgr.stop(task);
38012 this.initEditor.defer(10, this);
38019 Roo.TaskMgr.start(task);
38022 this.setSize(this.el.getSize());
38027 onResize : function(w, h){
38028 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38029 if(this.el && this.iframe){
38030 if(typeof w == 'number'){
38031 var aw = w - this.wrap.getFrameWidth('lr');
38032 this.el.setWidth(this.adjustWidth('textarea', aw));
38033 this.iframe.style.width = aw + 'px';
38035 if(typeof h == 'number'){
38037 for (var i =0; i < this.toolbars.length;i++) {
38038 // fixme - ask toolbars for heights?
38039 tbh += this.toolbars[i].tb.el.getHeight();
38045 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38046 this.el.setHeight(this.adjustWidth('textarea', ah));
38047 this.iframe.style.height = ah + 'px';
38049 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38056 * Toggles the editor between standard and source edit mode.
38057 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38059 toggleSourceEdit : function(sourceEditMode){
38061 this.sourceEditMode = sourceEditMode === true;
38063 if(this.sourceEditMode){
38066 this.iframe.className = 'x-hidden';
38067 this.el.removeClass('x-hidden');
38068 this.el.dom.removeAttribute('tabIndex');
38073 this.iframe.className = '';
38074 this.el.addClass('x-hidden');
38075 this.el.dom.setAttribute('tabIndex', -1);
38078 this.setSize(this.wrap.getSize());
38079 this.fireEvent('editmodechange', this, this.sourceEditMode);
38082 // private used internally
38083 createLink : function(){
38084 var url = prompt(this.createLinkText, this.defaultLinkValue);
38085 if(url && url != 'http:/'+'/'){
38086 this.relayCmd('createlink', url);
38090 // private (for BoxComponent)
38091 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38093 // private (for BoxComponent)
38094 getResizeEl : function(){
38098 // private (for BoxComponent)
38099 getPositionEl : function(){
38104 initEvents : function(){
38105 this.originalValue = this.getValue();
38109 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38112 markInvalid : Roo.emptyFn,
38114 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38117 clearInvalid : Roo.emptyFn,
38119 setValue : function(v){
38120 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38125 * Protected method that will not generally be called directly. If you need/want
38126 * custom HTML cleanup, this is the method you should override.
38127 * @param {String} html The HTML to be cleaned
38128 * return {String} The cleaned HTML
38130 cleanHtml : function(html){
38131 html = String(html);
38132 if(html.length > 5){
38133 if(Roo.isSafari){ // strip safari nonsense
38134 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38137 if(html == ' '){
38144 * Protected method that will not generally be called directly. Syncs the contents
38145 * of the editor iframe with the textarea.
38147 syncValue : function(){
38148 if(this.initialized){
38149 var bd = (this.doc.body || this.doc.documentElement);
38150 var html = bd.innerHTML;
38152 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38153 var m = bs.match(/text-align:(.*?);/i);
38155 html = '<div style="'+m[0]+'">' + html + '</div>';
38158 html = this.cleanHtml(html);
38159 if(this.fireEvent('beforesync', this, html) !== false){
38160 this.el.dom.value = html;
38161 this.fireEvent('sync', this, html);
38167 * Protected method that will not generally be called directly. Pushes the value of the textarea
38168 * into the iframe editor.
38170 pushValue : function(){
38171 if(this.initialized){
38172 var v = this.el.dom.value;
38176 if(this.fireEvent('beforepush', this, v) !== false){
38177 (this.doc.body || this.doc.documentElement).innerHTML = v;
38178 this.fireEvent('push', this, v);
38184 deferFocus : function(){
38185 this.focus.defer(10, this);
38189 focus : function(){
38190 if(this.win && !this.sourceEditMode){
38197 assignDocWin: function()
38199 var iframe = this.iframe;
38202 this.doc = iframe.contentWindow.document;
38203 this.win = iframe.contentWindow;
38205 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38206 this.win = Roo.get(this.frameId).dom.contentWindow;
38211 initEditor : function(){
38212 //console.log("INIT EDITOR");
38213 this.assignDocWin();
38217 this.doc.designMode="on";
38219 this.doc.write(this.getDocMarkup());
38222 var dbody = (this.doc.body || this.doc.documentElement);
38223 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38224 // this copies styles from the containing element into thsi one..
38225 // not sure why we need all of this..
38226 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38227 ss['background-attachment'] = 'fixed'; // w3c
38228 dbody.bgProperties = 'fixed'; // ie
38229 Roo.DomHelper.applyStyles(dbody, ss);
38230 Roo.EventManager.on(this.doc, {
38231 'mousedown': this.onEditorEvent,
38232 'dblclick': this.onEditorEvent,
38233 'click': this.onEditorEvent,
38234 'keyup': this.onEditorEvent,
38239 Roo.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
38241 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38242 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38244 this.initialized = true;
38246 this.fireEvent('initialize', this);
38251 onDestroy : function(){
38257 for (var i =0; i < this.toolbars.length;i++) {
38258 // fixme - ask toolbars for heights?
38259 this.toolbars[i].onDestroy();
38262 this.wrap.dom.innerHTML = '';
38263 this.wrap.remove();
38268 onFirstFocus : function(){
38270 this.assignDocWin();
38273 this.activated = true;
38274 for (var i =0; i < this.toolbars.length;i++) {
38275 this.toolbars[i].onFirstFocus();
38278 if(Roo.isGecko){ // prevent silly gecko errors
38280 var s = this.win.getSelection();
38281 if(!s.focusNode || s.focusNode.nodeType != 3){
38282 var r = s.getRangeAt(0);
38283 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38288 this.execCmd('useCSS', true);
38289 this.execCmd('styleWithCSS', false);
38292 this.fireEvent('activate', this);
38296 adjustFont: function(btn){
38297 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38298 //if(Roo.isSafari){ // safari
38301 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38302 if(Roo.isSafari){ // safari
38303 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38304 v = (v < 10) ? 10 : v;
38305 v = (v > 48) ? 48 : v;
38306 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38311 v = Math.max(1, v+adjust);
38313 this.execCmd('FontSize', v );
38316 onEditorEvent : function(e){
38317 this.fireEvent('editorevent', this, e);
38318 // this.updateToolbar();
38322 insertTag : function(tg)
38324 // could be a bit smarter... -> wrap the current selected tRoo..
38326 this.execCmd("formatblock", tg);
38330 insertText : function(txt)
38334 range = this.createRange();
38335 range.deleteContents();
38336 //alert(Sender.getAttribute('label'));
38338 range.insertNode(this.doc.createTextNode(txt));
38342 relayBtnCmd : function(btn){
38343 this.relayCmd(btn.cmd);
38347 * Executes a Midas editor command on the editor document and performs necessary focus and
38348 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38349 * @param {String} cmd The Midas command
38350 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38352 relayCmd : function(cmd, value){
38354 this.execCmd(cmd, value);
38355 this.fireEvent('editorevent', this);
38356 //this.updateToolbar();
38361 * Executes a Midas editor command directly on the editor document.
38362 * For visual commands, you should use {@link #relayCmd} instead.
38363 * <b>This should only be called after the editor is initialized.</b>
38364 * @param {String} cmd The Midas command
38365 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38367 execCmd : function(cmd, value){
38368 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38373 applyCommand : function(e){
38375 var c = e.getCharCode(), cmd;
38377 c = String.fromCharCode(c);
38393 e.preventDefault();
38400 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38402 * @param {String} text
38404 insertAtCursor : function(text){
38405 if(!this.activated){
38410 var r = this.doc.selection.createRange();
38417 }else if(Roo.isGecko || Roo.isOpera){
38419 this.execCmd('InsertHTML', text);
38421 }else if(Roo.isSafari){
38422 this.execCmd('InsertText', text);
38428 fixKeys : function(){ // load time branching for fastest keydown performance
38430 return function(e){
38431 var k = e.getKey(), r;
38434 r = this.doc.selection.createRange();
38437 r.pasteHTML('    ');
38440 }else if(k == e.ENTER){
38441 r = this.doc.selection.createRange();
38443 var target = r.parentElement();
38444 if(!target || target.tagName.toLowerCase() != 'li'){
38446 r.pasteHTML('<br />');
38453 }else if(Roo.isOpera){
38454 return function(e){
38455 var k = e.getKey();
38459 this.execCmd('InsertHTML','    ');
38463 }else if(Roo.isSafari){
38464 return function(e){
38465 var k = e.getKey();
38468 this.execCmd('InsertText','\t');
38475 getAllAncestors: function()
38477 var p = this.getSelectedNode();
38480 a.push(p); // push blank onto stack..
38481 p = this.getParentElement();
38485 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38489 a.push(this.doc.body);
38493 lastSelNode : false,
38496 getSelection : function()
38498 this.assignDocWin();
38499 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38502 getSelectedNode: function()
38504 // this may only work on Gecko!!!
38506 // should we cache this!!!!
38511 var range = this.createRange(this.getSelection());
38514 var parent = range.parentElement();
38516 var testRange = range.duplicate();
38517 testRange.moveToElementText(parent);
38518 if (testRange.inRange(range)) {
38521 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38524 parent = parent.parentElement;
38530 var ar = range.endContainer.childNodes;
38532 ar = range.commonAncestorContainer.childNodes;
38533 //alert(ar.length);
38536 var other_nodes = [];
38537 var has_other_nodes = false;
38538 for (var i=0;i<ar.length;i++) {
38539 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
38542 // fullly contained node.
38544 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
38549 // probably selected..
38550 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
38551 other_nodes.push(ar[i]);
38554 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
38559 has_other_nodes = true;
38561 if (!nodes.length && other_nodes.length) {
38562 nodes= other_nodes;
38564 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
38570 createRange: function(sel)
38572 // this has strange effects when using with
38573 // top toolbar - not sure if it's a great idea.
38574 //this.editor.contentWindow.focus();
38575 if (typeof sel != "undefined") {
38577 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
38579 return this.doc.createRange();
38582 return this.doc.createRange();
38585 getParentElement: function()
38588 this.assignDocWin();
38589 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
38591 var range = this.createRange(sel);
38594 var p = range.commonAncestorContainer;
38595 while (p.nodeType == 3) { // text node
38607 // BC Hacks - cause I cant work out what i was trying to do..
38608 rangeIntersectsNode : function(range, node)
38610 var nodeRange = node.ownerDocument.createRange();
38612 nodeRange.selectNode(node);
38615 nodeRange.selectNodeContents(node);
38618 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
38619 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
38621 rangeCompareNode : function(range, node) {
38622 var nodeRange = node.ownerDocument.createRange();
38624 nodeRange.selectNode(node);
38626 nodeRange.selectNodeContents(node);
38628 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
38629 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
38631 if (nodeIsBefore && !nodeIsAfter)
38633 if (!nodeIsBefore && nodeIsAfter)
38635 if (nodeIsBefore && nodeIsAfter)
38643 // hide stuff that is not compatible
38657 * @event specialkey
38661 * @cfg {String} fieldClass @hide
38664 * @cfg {String} focusClass @hide
38667 * @cfg {String} autoCreate @hide
38670 * @cfg {String} inputType @hide
38673 * @cfg {String} invalidClass @hide
38676 * @cfg {String} invalidText @hide
38679 * @cfg {String} msgFx @hide
38682 * @cfg {String} validateOnBlur @hide
38684 });// <script type="text/javascript">
38687 * Ext JS Library 1.1.1
38688 * Copyright(c) 2006-2007, Ext JS, LLC.
38694 * @class Roo.form.HtmlEditorToolbar1
38699 new Roo.form.HtmlEditor({
38702 new Roo.form.HtmlEditorToolbar1({
38703 disable : { fonts: 1 , format: 1, ..., ... , ...],
38709 * @cfg {Object} disable List of elements to disable..
38710 * @cfg {Array} btns List of additional buttons.
38714 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
38717 Roo.form.HtmlEditor.ToolbarStandard = function(config)
38720 Roo.apply(this, config);
38721 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
38722 // dont call parent... till later.
38725 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
38733 * @cfg {Object} disable List of toolbar elements to disable
38738 * @cfg {Array} fontFamilies An array of available font families
38756 // "á" , ?? a acute?
38761 "°" // , // degrees
38763 // "é" , // e ecute
38764 // "ú" , // u ecute?
38767 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
38768 "input:submit", "input:button", "select", "textarea", "label" ],
38771 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
38773 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
38776 * @cfg {String} defaultFont default font to use.
38778 defaultFont: 'tahoma',
38780 fontSelect : false,
38783 formatCombo : false,
38785 init : function(editor)
38787 this.editor = editor;
38790 var fid = editor.frameId;
38792 function btn(id, toggle, handler){
38793 var xid = fid + '-'+ id ;
38797 cls : 'x-btn-icon x-edit-'+id,
38798 enableToggle:toggle !== false,
38799 scope: editor, // was editor...
38800 handler:handler||editor.relayBtnCmd,
38801 clickEvent:'mousedown',
38802 tooltip: etb.buttonTips[id] || undefined, ///tips ???
38809 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
38811 // stop form submits
38812 tb.el.on('click', function(e){
38813 e.preventDefault(); // what does this do?
38816 if(!this.disable.font && !Roo.isSafari){
38817 /* why no safari for fonts
38818 editor.fontSelect = tb.el.createChild({
38821 cls:'x-font-select',
38822 html: editor.createFontOptions()
38824 editor.fontSelect.on('change', function(){
38825 var font = editor.fontSelect.dom.value;
38826 editor.relayCmd('fontname', font);
38827 editor.deferFocus();
38830 editor.fontSelect.dom,
38835 if(!this.disable.formats){
38836 this.formatCombo = new Roo.form.ComboBox({
38837 store: new Roo.data.SimpleStore({
38840 data : this.formats // from states.js
38843 //autoCreate : {tag: "div", size: "20"},
38844 displayField:'tag',
38848 triggerAction: 'all',
38849 emptyText:'Add tag',
38850 selectOnFocus:true,
38853 'select': function(c, r, i) {
38854 editor.insertTag(r.get('tag'));
38860 tb.addField(this.formatCombo);
38864 if(!this.disable.format){
38871 if(!this.disable.fontSize){
38876 btn('increasefontsize', false, editor.adjustFont),
38877 btn('decreasefontsize', false, editor.adjustFont)
38882 if(this.disable.colors){
38885 id:editor.frameId +'-forecolor',
38886 cls:'x-btn-icon x-edit-forecolor',
38887 clickEvent:'mousedown',
38888 tooltip: this.buttonTips['forecolor'] || undefined,
38890 menu : new Roo.menu.ColorMenu({
38891 allowReselect: true,
38892 focus: Roo.emptyFn,
38895 selectHandler: function(cp, color){
38896 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
38897 editor.deferFocus();
38900 clickEvent:'mousedown'
38903 id:editor.frameId +'backcolor',
38904 cls:'x-btn-icon x-edit-backcolor',
38905 clickEvent:'mousedown',
38906 tooltip: this.buttonTips['backcolor'] || undefined,
38908 menu : new Roo.menu.ColorMenu({
38909 focus: Roo.emptyFn,
38912 allowReselect: true,
38913 selectHandler: function(cp, color){
38915 editor.execCmd('useCSS', false);
38916 editor.execCmd('hilitecolor', color);
38917 editor.execCmd('useCSS', true);
38918 editor.deferFocus();
38920 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
38921 Roo.isSafari || Roo.isIE ? '#'+color : color);
38922 editor.deferFocus();
38926 clickEvent:'mousedown'
38931 // now add all the items...
38934 if(!this.disable.alignments){
38937 btn('justifyleft'),
38938 btn('justifycenter'),
38939 btn('justifyright')
38943 //if(!Roo.isSafari){
38944 if(!this.disable.links){
38947 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
38951 if(!this.disable.lists){
38954 btn('insertorderedlist'),
38955 btn('insertunorderedlist')
38958 if(!this.disable.sourceEdit){
38961 btn('sourceedit', true, function(btn){
38962 this.toggleSourceEdit(btn.pressed);
38969 // special menu.. - needs to be tidied up..
38970 if (!this.disable.special) {
38973 cls: 'x-edit-none',
38978 for (var i =0; i < this.specialChars.length; i++) {
38979 smenu.menu.items.push({
38981 text: this.specialChars[i],
38982 handler: function(a,b) {
38983 editor.insertAtCursor(String.fromCharCode(a.text.replace('&#','').replace(';', '')));
38995 for(var i =0; i< this.btns.length;i++) {
38996 var b = this.btns[i];
38997 b.cls = 'x-edit-none';
39006 // disable everything...
39008 this.tb.items.each(function(item){
39009 if(item.id != editor.frameId+ '-sourceedit'){
39013 this.rendered = true;
39015 // the all the btns;
39016 editor.on('editorevent', this.updateToolbar, this);
39017 // other toolbars need to implement this..
39018 //editor.on('editmodechange', this.updateToolbar, this);
39024 * Protected method that will not generally be called directly. It triggers
39025 * a toolbar update by reading the markup state of the current selection in the editor.
39027 updateToolbar: function(){
39029 if(!this.editor.activated){
39030 this.editor.onFirstFocus();
39034 var btns = this.tb.items.map,
39035 doc = this.editor.doc,
39036 frameId = this.editor.frameId;
39038 if(!this.disable.font && !Roo.isSafari){
39040 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39041 if(name != this.fontSelect.dom.value){
39042 this.fontSelect.dom.value = name;
39046 if(!this.disable.format){
39047 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39048 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39049 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39051 if(!this.disable.alignments){
39052 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39053 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39054 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39056 if(!Roo.isSafari && !this.disable.lists){
39057 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39058 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39061 var ans = this.editor.getAllAncestors();
39062 if (this.formatCombo) {
39065 var store = this.formatCombo.store;
39066 this.formatCombo.setValue("");
39067 for (var i =0; i < ans.length;i++) {
39068 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), true).length) {
39070 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39078 // hides menus... - so this cant be on a menu...
39079 Roo.menu.MenuMgr.hideAll();
39081 //this.editorsyncValue();
39085 createFontOptions : function(){
39086 var buf = [], fs = this.fontFamilies, ff, lc;
39087 for(var i = 0, len = fs.length; i< len; i++){
39089 lc = ff.toLowerCase();
39091 '<option value="',lc,'" style="font-family:',ff,';"',
39092 (this.defaultFont == lc ? ' selected="true">' : '>'),
39097 return buf.join('');
39100 toggleSourceEdit : function(sourceEditMode){
39101 if(sourceEditMode === undefined){
39102 sourceEditMode = !this.sourceEditMode;
39104 this.sourceEditMode = sourceEditMode === true;
39105 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39106 // just toggle the button?
39107 if(btn.pressed !== this.editor.sourceEditMode){
39108 btn.toggle(this.editor.sourceEditMode);
39112 if(this.sourceEditMode){
39113 this.tb.items.each(function(item){
39114 if(item.cmd != 'sourceedit'){
39120 if(this.initialized){
39121 this.tb.items.each(function(item){
39127 // tell the editor that it's been pressed..
39128 this.editor.toggleSourceEdit(sourceEditMode);
39132 * Object collection of toolbar tooltips for the buttons in the editor. The key
39133 * is the command id associated with that button and the value is a valid QuickTips object.
39138 title: 'Bold (Ctrl+B)',
39139 text: 'Make the selected text bold.',
39140 cls: 'x-html-editor-tip'
39143 title: 'Italic (Ctrl+I)',
39144 text: 'Make the selected text italic.',
39145 cls: 'x-html-editor-tip'
39153 title: 'Bold (Ctrl+B)',
39154 text: 'Make the selected text bold.',
39155 cls: 'x-html-editor-tip'
39158 title: 'Italic (Ctrl+I)',
39159 text: 'Make the selected text italic.',
39160 cls: 'x-html-editor-tip'
39163 title: 'Underline (Ctrl+U)',
39164 text: 'Underline the selected text.',
39165 cls: 'x-html-editor-tip'
39167 increasefontsize : {
39168 title: 'Grow Text',
39169 text: 'Increase the font size.',
39170 cls: 'x-html-editor-tip'
39172 decreasefontsize : {
39173 title: 'Shrink Text',
39174 text: 'Decrease the font size.',
39175 cls: 'x-html-editor-tip'
39178 title: 'Text Highlight Color',
39179 text: 'Change the background color of the selected text.',
39180 cls: 'x-html-editor-tip'
39183 title: 'Font Color',
39184 text: 'Change the color of the selected text.',
39185 cls: 'x-html-editor-tip'
39188 title: 'Align Text Left',
39189 text: 'Align text to the left.',
39190 cls: 'x-html-editor-tip'
39193 title: 'Center Text',
39194 text: 'Center text in the editor.',
39195 cls: 'x-html-editor-tip'
39198 title: 'Align Text Right',
39199 text: 'Align text to the right.',
39200 cls: 'x-html-editor-tip'
39202 insertunorderedlist : {
39203 title: 'Bullet List',
39204 text: 'Start a bulleted list.',
39205 cls: 'x-html-editor-tip'
39207 insertorderedlist : {
39208 title: 'Numbered List',
39209 text: 'Start a numbered list.',
39210 cls: 'x-html-editor-tip'
39213 title: 'Hyperlink',
39214 text: 'Make the selected text a hyperlink.',
39215 cls: 'x-html-editor-tip'
39218 title: 'Source Edit',
39219 text: 'Switch to source editing mode.',
39220 cls: 'x-html-editor-tip'
39224 onDestroy : function(){
39227 this.tb.items.each(function(item){
39229 item.menu.removeAll();
39231 item.menu.el.destroy();
39239 onFirstFocus: function() {
39240 this.tb.items.each(function(item){
39249 // <script type="text/javascript">
39252 * Ext JS Library 1.1.1
39253 * Copyright(c) 2006-2007, Ext JS, LLC.
39260 * @class Roo.form.HtmlEditor.ToolbarContext
39265 new Roo.form.HtmlEditor({
39268 new Roo.form.HtmlEditor.ToolbarStandard(),
39269 new Roo.form.HtmlEditor.ToolbarContext()
39274 * @config : {Object} disable List of elements to disable.. (not done yet.)
39279 Roo.form.HtmlEditor.ToolbarContext = function(config)
39282 Roo.apply(this, config);
39283 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39284 // dont call parent... till later.
39286 Roo.form.HtmlEditor.ToolbarContext.types = {
39298 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39360 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39365 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
39429 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
39437 * @cfg {Object} disable List of toolbar elements to disable
39446 init : function(editor)
39448 this.editor = editor;
39451 var fid = editor.frameId;
39453 function btn(id, toggle, handler){
39454 var xid = fid + '-'+ id ;
39458 cls : 'x-btn-icon x-edit-'+id,
39459 enableToggle:toggle !== false,
39460 scope: editor, // was editor...
39461 handler:handler||editor.relayBtnCmd,
39462 clickEvent:'mousedown',
39463 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39467 // create a new element.
39468 var wdiv = editor.wrap.createChild({
39470 }, editor.wrap.dom.firstChild.nextSibling, true);
39472 // can we do this more than once??
39474 // stop form submits
39477 // disable everything...
39478 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39479 this.toolbars = {};
39481 for (var i in ty) {
39482 this.toolbars[i] = this.buildToolbar(ty[i],i);
39484 this.tb = this.toolbars.BODY;
39488 this.rendered = true;
39490 // the all the btns;
39491 editor.on('editorevent', this.updateToolbar, this);
39492 // other toolbars need to implement this..
39493 //editor.on('editmodechange', this.updateToolbar, this);
39499 * Protected method that will not generally be called directly. It triggers
39500 * a toolbar update by reading the markup state of the current selection in the editor.
39502 updateToolbar: function(){
39504 if(!this.editor.activated){
39505 this.editor.onFirstFocus();
39510 var ans = this.editor.getAllAncestors();
39513 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39514 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
39515 sel = sel ? sel : this.editor.doc.body;
39516 sel = sel.tagName.length ? sel : this.editor.doc.body;
39517 var tn = sel.tagName.toUpperCase();
39518 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
39519 tn = sel.tagName.toUpperCase();
39520 if (this.tb.name == tn) {
39521 return; // no change
39524 ///console.log("show: " + tn);
39525 this.tb = this.toolbars[tn];
39527 this.tb.fields.each(function(e) {
39528 e.setValue(sel.getAttribute(e.name));
39530 this.tb.selectedNode = sel;
39533 Roo.menu.MenuMgr.hideAll();
39535 //this.editorsyncValue();
39540 onDestroy : function(){
39543 this.tb.items.each(function(item){
39545 item.menu.removeAll();
39547 item.menu.el.destroy();
39555 onFirstFocus: function() {
39556 // need to do this for all the toolbars..
39557 this.tb.items.each(function(item){
39561 buildToolbar: function(tlist, nm)
39563 var editor = this.editor;
39564 // create a new element.
39565 var wdiv = editor.wrap.createChild({
39567 }, editor.wrap.dom.firstChild.nextSibling, true);
39570 var tb = new Roo.Toolbar(wdiv);
39571 tb.add(nm+ ": ");
39572 for (var i in tlist) {
39573 var item = tlist[i];
39574 tb.add(item.title + ": ");
39579 tb.addField( new Roo.form.ComboBox({
39580 store: new Roo.data.SimpleStore({
39583 data : item.opts // from states.js
39586 displayField:'val',
39590 triggerAction: 'all',
39591 emptyText:'Select',
39592 selectOnFocus:true,
39593 width: item.width ? item.width : 130,
39595 'select': function(c, r, i) {
39596 tb.selectedNode.setAttribute(c.name, r.get('val'));
39607 tb.addField( new Roo.form.TextField({
39610 //allowBlank:false,
39615 tb.addField( new Roo.form.TextField({
39621 'change' : function(f, nv, ov) {
39622 tb.selectedNode.setAttribute(f.name, nv);
39628 tb.el.on('click', function(e){
39629 e.preventDefault(); // what does this do?
39631 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
39634 // dont need to disable them... as they will get hidden
39651 * Ext JS Library 1.1.1
39652 * Copyright(c) 2006-2007, Ext JS, LLC.
39654 * Originally Released Under LGPL - original licence link has changed is not relivant.
39657 * <script type="text/javascript">
39661 * @class Roo.form.BasicForm
39662 * @extends Roo.util.Observable
39663 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
39665 * @param {String/HTMLElement/Roo.Element} el The form element or its id
39666 * @param {Object} config Configuration options
39668 Roo.form.BasicForm = function(el, config){
39669 this.allItems = [];
39670 this.childForms = [];
39671 Roo.apply(this, config);
39673 * The Roo.form.Field items in this form.
39674 * @type MixedCollection
39678 this.items = new Roo.util.MixedCollection(false, function(o){
39679 return o.id || (o.id = Roo.id());
39683 * @event beforeaction
39684 * Fires before any action is performed. Return false to cancel the action.
39685 * @param {Form} this
39686 * @param {Action} action The action to be performed
39688 beforeaction: true,
39690 * @event actionfailed
39691 * Fires when an action fails.
39692 * @param {Form} this
39693 * @param {Action} action The action that failed
39695 actionfailed : true,
39697 * @event actioncomplete
39698 * Fires when an action is completed.
39699 * @param {Form} this
39700 * @param {Action} action The action that completed
39702 actioncomplete : true
39707 Roo.form.BasicForm.superclass.constructor.call(this);
39710 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
39712 * @cfg {String} method
39713 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
39716 * @cfg {DataReader} reader
39717 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
39718 * This is optional as there is built-in support for processing JSON.
39721 * @cfg {DataReader} errorReader
39722 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
39723 * This is completely optional as there is built-in support for processing JSON.
39726 * @cfg {String} url
39727 * The URL to use for form actions if one isn't supplied in the action options.
39730 * @cfg {Boolean} fileUpload
39731 * Set to true if this form is a file upload.
39734 * @cfg {Object} baseParams
39735 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
39738 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
39743 activeAction : null,
39746 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
39747 * or setValues() data instead of when the form was first created.
39749 trackResetOnLoad : false,
39753 * childForms - used for multi-tab forms
39756 childForms : false,
39759 * allItems - full list of fields.
39765 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
39766 * element by passing it or its id or mask the form itself by passing in true.
39769 waitMsgTarget : undefined,
39772 initEl : function(el){
39773 this.el = Roo.get(el);
39774 this.id = this.el.id || Roo.id();
39775 this.el.on('submit', this.onSubmit, this);
39776 this.el.addClass('x-form');
39780 onSubmit : function(e){
39785 * Returns true if client-side validation on the form is successful.
39788 isValid : function(){
39790 this.items.each(function(f){
39799 * Returns true if any fields in this form have changed since their original load.
39802 isDirty : function(){
39804 this.items.each(function(f){
39814 * Performs a predefined action (submit or load) or custom actions you define on this form.
39815 * @param {String} actionName The name of the action type
39816 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
39817 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
39818 * accept other config options):
39820 Property Type Description
39821 ---------------- --------------- ----------------------------------------------------------------------------------
39822 url String The url for the action (defaults to the form's url)
39823 method String The form method to use (defaults to the form's method, or POST if not defined)
39824 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
39825 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
39826 validate the form on the client (defaults to false)
39828 * @return {BasicForm} this
39830 doAction : function(action, options){
39831 if(typeof action == 'string'){
39832 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
39834 if(this.fireEvent('beforeaction', this, action) !== false){
39835 this.beforeAction(action);
39836 action.run.defer(100, action);
39842 * Shortcut to do a submit action.
39843 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39844 * @return {BasicForm} this
39846 submit : function(options){
39847 this.doAction('submit', options);
39852 * Shortcut to do a load action.
39853 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39854 * @return {BasicForm} this
39856 load : function(options){
39857 this.doAction('load', options);
39862 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
39863 * @param {Record} record The record to edit
39864 * @return {BasicForm} this
39866 updateRecord : function(record){
39867 record.beginEdit();
39868 var fs = record.fields;
39869 fs.each(function(f){
39870 var field = this.findField(f.name);
39872 record.set(f.name, field.getValue());
39880 * Loads an Roo.data.Record into this form.
39881 * @param {Record} record The record to load
39882 * @return {BasicForm} this
39884 loadRecord : function(record){
39885 this.setValues(record.data);
39890 beforeAction : function(action){
39891 var o = action.options;
39893 if(this.waitMsgTarget === true){
39894 this.el.mask(o.waitMsg, 'x-mask-loading');
39895 }else if(this.waitMsgTarget){
39896 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
39897 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
39899 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
39905 afterAction : function(action, success){
39906 this.activeAction = null;
39907 var o = action.options;
39909 if(this.waitMsgTarget === true){
39911 }else if(this.waitMsgTarget){
39912 this.waitMsgTarget.unmask();
39914 Roo.MessageBox.updateProgress(1);
39915 Roo.MessageBox.hide();
39922 Roo.callback(o.success, o.scope, [this, action]);
39923 this.fireEvent('actioncomplete', this, action);
39925 Roo.callback(o.failure, o.scope, [this, action]);
39926 this.fireEvent('actionfailed', this, action);
39931 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
39932 * @param {String} id The value to search for
39935 findField : function(id){
39936 var field = this.items.get(id);
39938 this.items.each(function(f){
39939 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
39945 return field || null;
39949 * Add a secondary form to this one,
39950 * Used to provide tabbed forms. One form is primary, with hidden values
39951 * which mirror the elements from the other forms.
39953 * @param {Roo.form.Form} form to add.
39956 addForm : function(form){
39958 this.childForms.push(form);
39959 Roo.each(form.allItems, function (fe) {
39961 if (this.findField(fe.name)) { // already added..
39964 this.add( new Roo.form.Hidden({
39971 * Mark fields in this form invalid in bulk.
39972 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
39973 * @return {BasicForm} this
39975 markInvalid : function(errors){
39976 if(errors instanceof Array){
39977 for(var i = 0, len = errors.length; i < len; i++){
39978 var fieldError = errors[i];
39979 var f = this.findField(fieldError.id);
39981 f.markInvalid(fieldError.msg);
39987 if(typeof errors[id] != 'function' && (field = this.findField(id))){
39988 field.markInvalid(errors[id]);
39992 Roo.each(this.childForms || [], function (f) {
39993 f.markInvalid(errors);
40000 * Set values for fields in this form in bulk.
40001 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40002 * @return {BasicForm} this
40004 setValues : function(values){
40005 if(values instanceof Array){ // array of objects
40006 for(var i = 0, len = values.length; i < len; i++){
40008 var f = this.findField(v.id);
40010 f.setValue(v.value);
40011 if(this.trackResetOnLoad){
40012 f.originalValue = f.getValue();
40016 }else{ // object hash
40019 if(typeof values[id] != 'function' && (field = this.findField(id))){
40021 if (field.setFromData &&
40022 field.valueField &&
40023 field.displayField &&
40024 // combos' with local stores can
40025 // be queried via setValue()
40026 // to set their value..
40027 (field.store && !field.store.isLocal)
40031 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40032 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40033 field.setFromData(sd);
40036 field.setValue(values[id]);
40040 if(this.trackResetOnLoad){
40041 field.originalValue = field.getValue();
40047 Roo.each(this.childForms || [], function (f) {
40048 f.setValues(values);
40055 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40056 * they are returned as an array.
40057 * @param {Boolean} asString
40060 getValues : function(asString){
40061 if (this.childForms) {
40062 // copy values from the child forms
40063 Roo.each(this.childForms, function (f) {
40065 Roo.each(f.allFields, function (e) {
40066 if (e.name && e.getValue && this.findField(e.name)) {
40067 this.findField(e.name).setValue(e.getValue());
40076 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40077 if(asString === true){
40080 return Roo.urlDecode(fs);
40084 * Clears all invalid messages in this form.
40085 * @return {BasicForm} this
40087 clearInvalid : function(){
40088 this.items.each(function(f){
40092 Roo.each(this.childForms || [], function (f) {
40101 * Resets this form.
40102 * @return {BasicForm} this
40104 reset : function(){
40105 this.items.each(function(f){
40109 Roo.each(this.childForms || [], function (f) {
40118 * Add Roo.form components to this form.
40119 * @param {Field} field1
40120 * @param {Field} field2 (optional)
40121 * @param {Field} etc (optional)
40122 * @return {BasicForm} this
40125 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40131 * Removes a field from the items collection (does NOT remove its markup).
40132 * @param {Field} field
40133 * @return {BasicForm} this
40135 remove : function(field){
40136 this.items.remove(field);
40141 * Looks at the fields in this form, checks them for an id attribute,
40142 * and calls applyTo on the existing dom element with that id.
40143 * @return {BasicForm} this
40145 render : function(){
40146 this.items.each(function(f){
40147 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40155 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40156 * @param {Object} values
40157 * @return {BasicForm} this
40159 applyToFields : function(o){
40160 this.items.each(function(f){
40167 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40168 * @param {Object} values
40169 * @return {BasicForm} this
40171 applyIfToFields : function(o){
40172 this.items.each(function(f){
40180 Roo.BasicForm = Roo.form.BasicForm;/*
40182 * Ext JS Library 1.1.1
40183 * Copyright(c) 2006-2007, Ext JS, LLC.
40185 * Originally Released Under LGPL - original licence link has changed is not relivant.
40188 * <script type="text/javascript">
40192 * @class Roo.form.Form
40193 * @extends Roo.form.BasicForm
40194 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40196 * @param {Object} config Configuration options
40198 Roo.form.Form = function(config){
40200 if (config.items) {
40201 xitems = config.items;
40202 delete config.items;
40206 Roo.form.Form.superclass.constructor.call(this, null, config);
40207 this.url = this.url || this.action;
40209 this.root = new Roo.form.Layout(Roo.applyIf({
40213 this.active = this.root;
40215 * Array of all the buttons that have been added to this form via {@link addButton}
40219 this.allItems = [];
40222 * @event clientvalidation
40223 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40224 * @param {Form} this
40225 * @param {Boolean} valid true if the form has passed client-side validation
40227 clientvalidation: true,
40230 * Fires when the form is rendered
40231 * @param {Roo.form.Form} form
40236 Roo.each(xitems, this.addxtype, this);
40242 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40244 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40247 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40250 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40252 buttonAlign:'center',
40255 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40260 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40261 * This property cascades to child containers if not set.
40266 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40267 * fires a looping event with that state. This is required to bind buttons to the valid
40268 * state using the config value formBind:true on the button.
40270 monitorValid : false,
40273 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40279 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40280 * fields are added and the column is closed. If no fields are passed the column remains open
40281 * until end() is called.
40282 * @param {Object} config The config to pass to the column
40283 * @param {Field} field1 (optional)
40284 * @param {Field} field2 (optional)
40285 * @param {Field} etc (optional)
40286 * @return Column The column container object
40288 column : function(c){
40289 var col = new Roo.form.Column(c);
40291 if(arguments.length > 1){ // duplicate code required because of Opera
40292 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40299 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40300 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40301 * until end() is called.
40302 * @param {Object} config The config to pass to the fieldset
40303 * @param {Field} field1 (optional)
40304 * @param {Field} field2 (optional)
40305 * @param {Field} etc (optional)
40306 * @return FieldSet The fieldset container object
40308 fieldset : function(c){
40309 var fs = new Roo.form.FieldSet(c);
40311 if(arguments.length > 1){ // duplicate code required because of Opera
40312 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40319 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40320 * fields are added and the container is closed. If no fields are passed the container remains open
40321 * until end() is called.
40322 * @param {Object} config The config to pass to the Layout
40323 * @param {Field} field1 (optional)
40324 * @param {Field} field2 (optional)
40325 * @param {Field} etc (optional)
40326 * @return Layout The container object
40328 container : function(c){
40329 var l = new Roo.form.Layout(c);
40331 if(arguments.length > 1){ // duplicate code required because of Opera
40332 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40339 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
40340 * @param {Object} container A Roo.form.Layout or subclass of Layout
40341 * @return {Form} this
40343 start : function(c){
40344 // cascade label info
40345 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
40346 this.active.stack.push(c);
40347 c.ownerCt = this.active;
40353 * Closes the current open container
40354 * @return {Form} this
40357 if(this.active == this.root){
40360 this.active = this.active.ownerCt;
40365 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
40366 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
40367 * as the label of the field.
40368 * @param {Field} field1
40369 * @param {Field} field2 (optional)
40370 * @param {Field} etc. (optional)
40371 * @return {Form} this
40374 this.active.stack.push.apply(this.active.stack, arguments);
40375 this.allItems.push.apply(this.allItems,arguments);
40377 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
40378 if(a[i].isFormField){
40383 Roo.form.Form.superclass.add.apply(this, r);
40393 * Find any element that has been added to a form, using it's ID or name
40394 * This can include framesets, columns etc. along with regular fields..
40395 * @param {String} id - id or name to find.
40397 * @return {Element} e - or false if nothing found.
40399 findbyId : function(id)
40405 Ext.each(this.allItems, function(f){
40406 if (f.id == id || f.name == id ){
40417 * Render this form into the passed container. This should only be called once!
40418 * @param {String/HTMLElement/Element} container The element this component should be rendered into
40419 * @return {Form} this
40421 render : function(ct){
40423 var o = this.autoCreate || {
40425 method : this.method || 'POST',
40426 id : this.id || Roo.id()
40428 this.initEl(ct.createChild(o));
40430 this.root.render(this.el);
40432 this.items.each(function(f){
40433 f.render('x-form-el-'+f.id);
40436 if(this.buttons.length > 0){
40437 // tables are required to maintain order and for correct IE layout
40438 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
40439 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
40440 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
40442 var tr = tb.getElementsByTagName('tr')[0];
40443 for(var i = 0, len = this.buttons.length; i < len; i++) {
40444 var b = this.buttons[i];
40445 var td = document.createElement('td');
40446 td.className = 'x-form-btn-td';
40447 b.render(tr.appendChild(td));
40450 if(this.monitorValid){ // initialize after render
40451 this.startMonitoring();
40453 this.fireEvent('rendered', this);
40458 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
40459 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
40460 * object or a valid Roo.DomHelper element config
40461 * @param {Function} handler The function called when the button is clicked
40462 * @param {Object} scope (optional) The scope of the handler function
40463 * @return {Roo.Button}
40465 addButton : function(config, handler, scope){
40469 minWidth: this.minButtonWidth,
40472 if(typeof config == "string"){
40475 Roo.apply(bc, config);
40477 var btn = new Roo.Button(null, bc);
40478 this.buttons.push(btn);
40483 * Adds a series of form elements (using the xtype property as the factory method.
40484 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
40485 * @param {Object} config
40488 addxtype : function()
40490 var ar = Array.prototype.slice.call(arguments, 0);
40492 for(var i = 0; i < ar.length; i++) {
40494 continue; // skip -- if this happends something invalid got sent, we
40495 // should ignore it, as basically that interface element will not show up
40496 // and that should be pretty obvious!!
40499 if (Roo.form[ar[i].xtype]) {
40501 var fe = Roo.factory(ar[i], Roo.form);
40507 fe.store.form = this;
40512 this.allItems.push(fe);
40513 if (fe.items && fe.addxtype) {
40514 fe.addxtype.apply(fe, fe.items);
40524 // console.log('adding ' + ar[i].xtype);
40526 if (ar[i].xtype == 'Button') {
40527 //console.log('adding button');
40528 //console.log(ar[i]);
40529 this.addButton(ar[i]);
40530 this.allItems.push(fe);
40534 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
40535 alert('end is not supported on xtype any more, use items');
40537 // //console.log('adding end');
40545 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
40546 * option "monitorValid"
40548 startMonitoring : function(){
40551 Roo.TaskMgr.start({
40552 run : this.bindHandler,
40553 interval : this.monitorPoll || 200,
40560 * Stops monitoring of the valid state of this form
40562 stopMonitoring : function(){
40563 this.bound = false;
40567 bindHandler : function(){
40569 return false; // stops binding
40572 this.items.each(function(f){
40573 if(!f.isValid(true)){
40578 for(var i = 0, len = this.buttons.length; i < len; i++){
40579 var btn = this.buttons[i];
40580 if(btn.formBind === true && btn.disabled === valid){
40581 btn.setDisabled(!valid);
40584 this.fireEvent('clientvalidation', this, valid);
40598 Roo.Form = Roo.form.Form;
40601 * Ext JS Library 1.1.1
40602 * Copyright(c) 2006-2007, Ext JS, LLC.
40604 * Originally Released Under LGPL - original licence link has changed is not relivant.
40607 * <script type="text/javascript">
40611 * @class Roo.form.Action
40612 * Internal Class used to handle form actions
40614 * @param {Roo.form.BasicForm} el The form element or its id
40615 * @param {Object} config Configuration options
40619 // define the action interface
40620 Roo.form.Action = function(form, options){
40622 this.options = options || {};
40625 * Client Validation Failed
40628 Roo.form.Action.CLIENT_INVALID = 'client';
40630 * Server Validation Failed
40633 Roo.form.Action.SERVER_INVALID = 'server';
40635 * Connect to Server Failed
40638 Roo.form.Action.CONNECT_FAILURE = 'connect';
40640 * Reading Data from Server Failed
40643 Roo.form.Action.LOAD_FAILURE = 'load';
40645 Roo.form.Action.prototype = {
40647 failureType : undefined,
40648 response : undefined,
40649 result : undefined,
40651 // interface method
40652 run : function(options){
40656 // interface method
40657 success : function(response){
40661 // interface method
40662 handleResponse : function(response){
40666 // default connection failure
40667 failure : function(response){
40668 this.response = response;
40669 this.failureType = Roo.form.Action.CONNECT_FAILURE;
40670 this.form.afterAction(this, false);
40673 processResponse : function(response){
40674 this.response = response;
40675 if(!response.responseText){
40678 this.result = this.handleResponse(response);
40679 return this.result;
40682 // utility functions used internally
40683 getUrl : function(appendParams){
40684 var url = this.options.url || this.form.url || this.form.el.dom.action;
40686 var p = this.getParams();
40688 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
40694 getMethod : function(){
40695 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
40698 getParams : function(){
40699 var bp = this.form.baseParams;
40700 var p = this.options.params;
40702 if(typeof p == "object"){
40703 p = Roo.urlEncode(Roo.applyIf(p, bp));
40704 }else if(typeof p == 'string' && bp){
40705 p += '&' + Roo.urlEncode(bp);
40708 p = Roo.urlEncode(bp);
40713 createCallback : function(){
40715 success: this.success,
40716 failure: this.failure,
40718 timeout: (this.form.timeout*1000),
40719 upload: this.form.fileUpload ? this.success : undefined
40724 Roo.form.Action.Submit = function(form, options){
40725 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
40728 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
40732 var o = this.options;
40733 var method = this.getMethod();
40734 var isPost = method == 'POST';
40735 if(o.clientValidation === false || this.form.isValid()){
40736 Roo.Ajax.request(Roo.apply(this.createCallback(), {
40737 form:this.form.el.dom,
40738 url:this.getUrl(!isPost),
40740 params:isPost ? this.getParams() : null,
40741 isUpload: this.form.fileUpload
40744 }else if (o.clientValidation !== false){ // client validation failed
40745 this.failureType = Roo.form.Action.CLIENT_INVALID;
40746 this.form.afterAction(this, false);
40750 success : function(response){
40751 var result = this.processResponse(response);
40752 if(result === true || result.success){
40753 this.form.afterAction(this, true);
40757 this.form.markInvalid(result.errors);
40758 this.failureType = Roo.form.Action.SERVER_INVALID;
40760 this.form.afterAction(this, false);
40763 handleResponse : function(response){
40764 if(this.form.errorReader){
40765 var rs = this.form.errorReader.read(response);
40768 for(var i = 0, len = rs.records.length; i < len; i++) {
40769 var r = rs.records[i];
40770 errors[i] = r.data;
40773 if(errors.length < 1){
40777 success : rs.success,
40783 ret = Roo.decode(response.responseText);
40787 errorMsg: "Failed to read server message: " + response.responseText,
40797 Roo.form.Action.Load = function(form, options){
40798 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
40799 this.reader = this.form.reader;
40802 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
40806 Roo.Ajax.request(Roo.apply(
40807 this.createCallback(), {
40808 method:this.getMethod(),
40809 url:this.getUrl(false),
40810 params:this.getParams()
40814 success : function(response){
40815 var result = this.processResponse(response);
40816 if(result === true || !result.success || !result.data){
40817 this.failureType = Roo.form.Action.LOAD_FAILURE;
40818 this.form.afterAction(this, false);
40821 this.form.clearInvalid();
40822 this.form.setValues(result.data);
40823 this.form.afterAction(this, true);
40826 handleResponse : function(response){
40827 if(this.form.reader){
40828 var rs = this.form.reader.read(response);
40829 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
40831 success : rs.success,
40835 return Roo.decode(response.responseText);
40839 Roo.form.Action.ACTION_TYPES = {
40840 'load' : Roo.form.Action.Load,
40841 'submit' : Roo.form.Action.Submit
40844 * Ext JS Library 1.1.1
40845 * Copyright(c) 2006-2007, Ext JS, LLC.
40847 * Originally Released Under LGPL - original licence link has changed is not relivant.
40850 * <script type="text/javascript">
40854 * @class Roo.form.Layout
40855 * @extends Roo.Component
40856 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
40858 * @param {Object} config Configuration options
40860 Roo.form.Layout = function(config){
40862 if (config.items) {
40863 xitems = config.items;
40864 delete config.items;
40866 Roo.form.Layout.superclass.constructor.call(this, config);
40868 Roo.each(xitems, this.addxtype, this);
40872 Roo.extend(Roo.form.Layout, Roo.Component, {
40874 * @cfg {String/Object} autoCreate
40875 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
40878 * @cfg {String/Object/Function} style
40879 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
40880 * a function which returns such a specification.
40883 * @cfg {String} labelAlign
40884 * Valid values are "left," "top" and "right" (defaults to "left")
40887 * @cfg {Number} labelWidth
40888 * Fixed width in pixels of all field labels (defaults to undefined)
40891 * @cfg {Boolean} clear
40892 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
40896 * @cfg {String} labelSeparator
40897 * The separator to use after field labels (defaults to ':')
40899 labelSeparator : ':',
40901 * @cfg {Boolean} hideLabels
40902 * True to suppress the display of field labels in this layout (defaults to false)
40904 hideLabels : false,
40907 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
40912 onRender : function(ct, position){
40913 if(this.el){ // from markup
40914 this.el = Roo.get(this.el);
40915 }else { // generate
40916 var cfg = this.getAutoCreate();
40917 this.el = ct.createChild(cfg, position);
40920 this.el.applyStyles(this.style);
40922 if(this.labelAlign){
40923 this.el.addClass('x-form-label-'+this.labelAlign);
40925 if(this.hideLabels){
40926 this.labelStyle = "display:none";
40927 this.elementStyle = "padding-left:0;";
40929 if(typeof this.labelWidth == 'number'){
40930 this.labelStyle = "width:"+this.labelWidth+"px;";
40931 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
40933 if(this.labelAlign == 'top'){
40934 this.labelStyle = "width:auto;";
40935 this.elementStyle = "padding-left:0;";
40938 var stack = this.stack;
40939 var slen = stack.length;
40941 if(!this.fieldTpl){
40942 var t = new Roo.Template(
40943 '<div class="x-form-item {5}">',
40944 '<label for="{0}" style="{2}">{1}{4}</label>',
40945 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40947 '</div><div class="x-form-clear-left"></div>'
40949 t.disableFormats = true;
40951 Roo.form.Layout.prototype.fieldTpl = t;
40953 for(var i = 0; i < slen; i++) {
40954 if(stack[i].isFormField){
40955 this.renderField(stack[i]);
40957 this.renderComponent(stack[i]);
40962 this.el.createChild({cls:'x-form-clear'});
40967 renderField : function(f){
40968 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
40971 f.labelStyle||this.labelStyle||'', //2
40972 this.elementStyle||'', //3
40973 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
40974 f.itemCls||this.itemCls||'' //5
40975 ], true).getPrevSibling());
40979 renderComponent : function(c){
40980 c.render(c.isLayout ? this.el : this.el.createChild());
40983 * Adds a object form elements (using the xtype property as the factory method.)
40984 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
40985 * @param {Object} config
40987 addxtype : function(o)
40989 // create the lement.
40990 o.form = this.form;
40991 var fe = Roo.factory(o, Roo.form);
40992 this.form.allItems.push(fe);
40993 this.stack.push(fe);
40995 if (fe.isFormField) {
40996 this.form.items.add(fe);
41004 * @class Roo.form.Column
41005 * @extends Roo.form.Layout
41006 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41008 * @param {Object} config Configuration options
41010 Roo.form.Column = function(config){
41011 Roo.form.Column.superclass.constructor.call(this, config);
41014 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41016 * @cfg {Number/String} width
41017 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41020 * @cfg {String/Object} autoCreate
41021 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41025 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41028 onRender : function(ct, position){
41029 Roo.form.Column.superclass.onRender.call(this, ct, position);
41031 this.el.setWidth(this.width);
41038 * @class Roo.form.Row
41039 * @extends Roo.form.Layout
41040 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41042 * @param {Object} config Configuration options
41046 Roo.form.Row = function(config){
41047 Roo.form.Row.superclass.constructor.call(this, config);
41050 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41052 * @cfg {Number/String} width
41053 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41056 * @cfg {Number/String} height
41057 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41059 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41063 onRender : function(ct, position){
41064 //console.log('row render');
41066 var t = new Roo.Template(
41067 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41068 '<label for="{0}" style="{2}">{1}{4}</label>',
41069 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41073 t.disableFormats = true;
41075 Roo.form.Layout.prototype.rowTpl = t;
41077 this.fieldTpl = this.rowTpl;
41079 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41080 var labelWidth = 100;
41082 if ((this.labelAlign != 'top')) {
41083 if (typeof this.labelWidth == 'number') {
41084 labelWidth = this.labelWidth
41086 this.padWidth = 20 + labelWidth;
41090 Roo.form.Column.superclass.onRender.call(this, ct, position);
41092 this.el.setWidth(this.width);
41095 this.el.setHeight(this.height);
41100 renderField : function(f){
41101 f.fieldEl = this.fieldTpl.append(this.el, [
41102 f.id, f.fieldLabel,
41103 f.labelStyle||this.labelStyle||'',
41104 this.elementStyle||'',
41105 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41106 f.itemCls||this.itemCls||'',
41107 f.width ? f.width + this.padWidth : 160 + this.padWidth
41114 * @class Roo.form.FieldSet
41115 * @extends Roo.form.Layout
41116 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41118 * @param {Object} config Configuration options
41120 Roo.form.FieldSet = function(config){
41121 Roo.form.FieldSet.superclass.constructor.call(this, config);
41124 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41126 * @cfg {String} legend
41127 * The text to display as the legend for the FieldSet (defaults to '')
41130 * @cfg {String/Object} autoCreate
41131 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41135 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41138 onRender : function(ct, position){
41139 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
41141 this.setLegend(this.legend);
41146 setLegend : function(text){
41148 this.el.child('legend').update(text);
41153 * Ext JS Library 1.1.1
41154 * Copyright(c) 2006-2007, Ext JS, LLC.
41156 * Originally Released Under LGPL - original licence link has changed is not relivant.
41159 * <script type="text/javascript">
41162 * @class Roo.form.VTypes
41163 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41166 Roo.form.VTypes = function(){
41167 // closure these in so they are only created once.
41168 var alpha = /^[a-zA-Z_]+$/;
41169 var alphanum = /^[a-zA-Z0-9_]+$/;
41170 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41171 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41173 // All these messages and functions are configurable
41176 * The function used to validate email addresses
41177 * @param {String} value The email address
41179 'email' : function(v){
41180 return email.test(v);
41183 * The error text to display when the email validation function returns false
41186 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41188 * The keystroke filter mask to be applied on email input
41191 'emailMask' : /[a-z0-9_\.\-@]/i,
41194 * The function used to validate URLs
41195 * @param {String} value The URL
41197 'url' : function(v){
41198 return url.test(v);
41201 * The error text to display when the url validation function returns false
41204 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41207 * The function used to validate alpha values
41208 * @param {String} value The value
41210 'alpha' : function(v){
41211 return alpha.test(v);
41214 * The error text to display when the alpha validation function returns false
41217 'alphaText' : 'This field should only contain letters and _',
41219 * The keystroke filter mask to be applied on alpha input
41222 'alphaMask' : /[a-z_]/i,
41225 * The function used to validate alphanumeric values
41226 * @param {String} value The value
41228 'alphanum' : function(v){
41229 return alphanum.test(v);
41232 * The error text to display when the alphanumeric validation function returns false
41235 'alphanumText' : 'This field should only contain letters, numbers and _',
41237 * The keystroke filter mask to be applied on alphanumeric input
41240 'alphanumMask' : /[a-z0-9_]/i
41242 }();//<script type="text/javascript">
41245 * @class Roo.form.FCKeditor
41246 * @extends Roo.form.TextArea
41247 * Wrapper around the FCKEditor http://www.fckeditor.net
41249 * Creates a new FCKeditor
41250 * @param {Object} config Configuration options
41252 Roo.form.FCKeditor = function(config){
41253 Roo.form.FCKeditor.superclass.constructor.call(this, config);
41256 * @event editorinit
41257 * Fired when the editor is initialized - you can add extra handlers here..
41258 * @param {FCKeditor} this
41259 * @param {Object} the FCK object.
41266 Roo.form.FCKeditor.editors = { };
41267 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
41269 //defaultAutoCreate : {
41270 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
41274 * @cfg {Object} fck options - see fck manual for details.
41279 * @cfg {Object} fck toolbar set (Basic or Default)
41281 toolbarSet : 'Basic',
41283 * @cfg {Object} fck BasePath
41285 basePath : '/fckeditor/',
41293 onRender : function(ct, position)
41296 this.defaultAutoCreate = {
41298 style:"width:300px;height:60px;",
41299 autocomplete: "off"
41302 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
41305 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
41306 if(this.preventScrollbars){
41307 this.el.setStyle("overflow", "hidden");
41309 this.el.setHeight(this.growMin);
41312 //console.log('onrender' + this.getId() );
41313 Roo.form.FCKeditor.editors[this.getId()] = this;
41316 this.replaceTextarea() ;
41320 getEditor : function() {
41321 return this.fckEditor;
41324 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
41325 * @param {Mixed} value The value to set
41329 setValue : function(value)
41331 //console.log('setValue: ' + value);
41333 if(typeof(value) == 'undefined') { // not sure why this is happending...
41336 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41338 //if(!this.el || !this.getEditor()) {
41339 // this.value = value;
41340 //this.setValue.defer(100,this,[value]);
41344 if(!this.getEditor()) {
41348 this.getEditor().SetData(value);
41355 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
41356 * @return {Mixed} value The field value
41358 getValue : function()
41361 if (this.frame && this.frame.dom.style.display == 'none') {
41362 return Roo.form.FCKeditor.superclass.getValue.call(this);
41365 if(!this.el || !this.getEditor()) {
41367 // this.getValue.defer(100,this);
41372 var value=this.getEditor().GetData();
41373 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41374 return Roo.form.FCKeditor.superclass.getValue.call(this);
41380 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
41381 * @return {Mixed} value The field value
41383 getRawValue : function()
41385 if (this.frame && this.frame.dom.style.display == 'none') {
41386 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41389 if(!this.el || !this.getEditor()) {
41390 //this.getRawValue.defer(100,this);
41397 var value=this.getEditor().GetData();
41398 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
41399 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41403 setSize : function(w,h) {
41407 //if (this.frame && this.frame.dom.style.display == 'none') {
41408 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41411 //if(!this.el || !this.getEditor()) {
41412 // this.setSize.defer(100,this, [w,h]);
41418 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41420 this.frame.dom.setAttribute('width', w);
41421 this.frame.dom.setAttribute('height', h);
41422 this.frame.setSize(w,h);
41426 toggleSourceEdit : function(value) {
41430 this.el.dom.style.display = value ? '' : 'none';
41431 this.frame.dom.style.display = value ? 'none' : '';
41436 focus: function(tag)
41438 if (this.frame.dom.style.display == 'none') {
41439 return Roo.form.FCKeditor.superclass.focus.call(this);
41441 if(!this.el || !this.getEditor()) {
41442 this.focus.defer(100,this, [tag]);
41449 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
41450 this.getEditor().Focus();
41452 if (!this.getEditor().Selection.GetSelection()) {
41453 this.focus.defer(100,this, [tag]);
41458 var r = this.getEditor().EditorDocument.createRange();
41459 r.setStart(tgs[0],0);
41460 r.setEnd(tgs[0],0);
41461 this.getEditor().Selection.GetSelection().removeAllRanges();
41462 this.getEditor().Selection.GetSelection().addRange(r);
41463 this.getEditor().Focus();
41470 replaceTextarea : function()
41472 if ( document.getElementById( this.getId() + '___Frame' ) )
41474 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
41476 // We must check the elements firstly using the Id and then the name.
41477 var oTextarea = document.getElementById( this.getId() );
41479 var colElementsByName = document.getElementsByName( this.getId() ) ;
41481 oTextarea.style.display = 'none' ;
41483 if ( oTextarea.tabIndex ) {
41484 this.TabIndex = oTextarea.tabIndex ;
41487 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
41488 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
41489 this.frame = Roo.get(this.getId() + '___Frame')
41492 _getConfigHtml : function()
41496 for ( var o in this.fckconfig ) {
41497 sConfig += sConfig.length > 0 ? '&' : '';
41498 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
41501 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
41505 _getIFrameHtml : function()
41507 var sFile = 'fckeditor.html' ;
41508 /* no idea what this is about..
41511 if ( (/fcksource=true/i).test( window.top.location.search ) )
41512 sFile = 'fckeditor.original.html' ;
41517 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
41518 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
41521 var html = '<iframe id="' + this.getId() +
41522 '___Frame" src="' + sLink +
41523 '" width="' + this.width +
41524 '" height="' + this.height + '"' +
41525 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
41526 ' frameborder="0" scrolling="no"></iframe>' ;
41531 _insertHtmlBefore : function( html, element )
41533 if ( element.insertAdjacentHTML ) {
41535 element.insertAdjacentHTML( 'beforeBegin', html ) ;
41537 var oRange = document.createRange() ;
41538 oRange.setStartBefore( element ) ;
41539 var oFragment = oRange.createContextualFragment( html );
41540 element.parentNode.insertBefore( oFragment, element ) ;
41553 //Roo.reg('fckeditor', Roo.form.FCKeditor);
41555 function FCKeditor_OnComplete(editorInstance){
41556 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
41557 f.fckEditor = editorInstance;
41558 //console.log("loaded");
41559 f.fireEvent('editorinit', f, editorInstance);
41579 //<script type="text/javascript">
41581 * @class Roo.form.GridField
41582 * @extends Roo.form.Field
41583 * Embed a grid (or editable grid into a form)
41586 * Creates a new GridField
41587 * @param {Object} config Configuration options
41589 Roo.form.GridField = function(config){
41590 Roo.form.GridField.superclass.constructor.call(this, config);
41594 Roo.extend(Roo.form.GridField, Roo.form.Field, {
41596 * @cfg {Number} width - used to restrict width of grid..
41600 * @cfg {Number} height - used to restrict height of grid..
41604 * @cfg {Object} xgrid (xtype'd description of grid) Grid or EditorGrid
41608 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41609 * {tag: "input", type: "checkbox", autocomplete: "off"})
41611 // defaultAutoCreate : { tag: 'div' },
41612 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
41614 * @cfg {String} addTitle Text to include for adding a title.
41618 onResize : function(){
41619 Roo.form.Field.superclass.onResize.apply(this, arguments);
41622 initEvents : function(){
41623 // Roo.form.Checkbox.superclass.initEvents.call(this);
41624 // has no events...
41629 getResizeEl : function(){
41633 getPositionEl : function(){
41638 onRender : function(ct, position){
41640 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
41641 var style = this.style;
41644 Roo.form.DisplayImage.superclass.onRender.call(this, ct, position);
41645 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
41646 this.viewEl = this.wrap.createChild({ tag: 'div' });
41648 this.viewEl.applyStyles(style);
41651 this.viewEl.setWidth(this.width);
41654 this.viewEl.setHeight(this.height);
41656 //if(this.inputValue !== undefined){
41657 //this.setValue(this.value);
41660 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
41663 this.grid.render();
41664 this.grid.getDataSource().on('remove', this.refreshValue, this);
41665 this.grid.getDataSource().on('update', this.refreshValue, this);
41666 this.grid.on('afteredit', this.refreshValue, this);
41672 * Sets the value of the item.
41673 * @param {String} either an object or a string..
41675 setValue : function(v){
41677 v = v || []; // empty set..
41678 // this does not seem smart - it really only affects memoryproxy grids..
41679 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
41680 var ds = this.grid.getDataSource();
41681 // assumes a json reader..
41683 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
41684 ds.loadData( data);
41686 Roo.form.GridField.superclass.setValue.call(this, v);
41687 this.refreshValue();
41688 // should load data in the grid really....
41692 refreshValue: function() {
41694 this.grid.getDataSource().each(function(r) {
41697 this.el.dom.value = Roo.encode(val);
41703 });//<script type="text/javasscript">
41707 * @class Roo.DDView
41708 * A DnD enabled version of Roo.View.
41709 * @param {Element/String} container The Element in which to create the View.
41710 * @param {String} tpl The template string used to create the markup for each element of the View
41711 * @param {Object} config The configuration properties. These include all the config options of
41712 * {@link Roo.View} plus some specific to this class.<br>
41714 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
41715 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
41717 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
41718 .x-view-drag-insert-above {
41719 border-top:1px dotted #3366cc;
41721 .x-view-drag-insert-below {
41722 border-bottom:1px dotted #3366cc;
41728 Roo.DDView = function(container, tpl, config) {
41729 Roo.DDView.superclass.constructor.apply(this, arguments);
41730 this.getEl().setStyle("outline", "0px none");
41731 this.getEl().unselectable();
41732 if (this.dragGroup) {
41733 this.setDraggable(this.dragGroup.split(","));
41735 if (this.dropGroup) {
41736 this.setDroppable(this.dropGroup.split(","));
41738 if (this.deletable) {
41739 this.setDeletable();
41741 this.isDirtyFlag = false;
41747 Roo.extend(Roo.DDView, Roo.View, {
41748 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
41749 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
41750 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
41751 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
41755 reset: Roo.emptyFn,
41757 clearInvalid: Roo.form.Field.prototype.clearInvalid,
41759 validate: function() {
41763 destroy: function() {
41764 this.purgeListeners();
41765 this.getEl.removeAllListeners();
41766 this.getEl().remove();
41767 if (this.dragZone) {
41768 if (this.dragZone.destroy) {
41769 this.dragZone.destroy();
41772 if (this.dropZone) {
41773 if (this.dropZone.destroy) {
41774 this.dropZone.destroy();
41779 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
41780 getName: function() {
41784 /** Loads the View from a JSON string representing the Records to put into the Store. */
41785 setValue: function(v) {
41787 throw "DDView.setValue(). DDView must be constructed with a valid Store";
41790 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
41791 this.store.proxy = new Roo.data.MemoryProxy(data);
41795 /** @return {String} a parenthesised list of the ids of the Records in the View. */
41796 getValue: function() {
41798 this.store.each(function(rec) {
41799 result += rec.id + ',';
41801 return result.substr(0, result.length - 1) + ')';
41804 getIds: function() {
41805 var i = 0, result = new Array(this.store.getCount());
41806 this.store.each(function(rec) {
41807 result[i++] = rec.id;
41812 isDirty: function() {
41813 return this.isDirtyFlag;
41817 * Part of the Roo.dd.DropZone interface. If no target node is found, the
41818 * whole Element becomes the target, and this causes the drop gesture to append.
41820 getTargetFromEvent : function(e) {
41821 var target = e.getTarget();
41822 while ((target !== null) && (target.parentNode != this.el.dom)) {
41823 target = target.parentNode;
41826 target = this.el.dom.lastChild || this.el.dom;
41832 * Create the drag data which consists of an object which has the property "ddel" as
41833 * the drag proxy element.
41835 getDragData : function(e) {
41836 var target = this.findItemFromChild(e.getTarget());
41838 this.handleSelection(e);
41839 var selNodes = this.getSelectedNodes();
41842 copy: this.copy || (this.allowCopy && e.ctrlKey),
41846 var selectedIndices = this.getSelectedIndexes();
41847 for (var i = 0; i < selectedIndices.length; i++) {
41848 dragData.records.push(this.store.getAt(selectedIndices[i]));
41850 if (selNodes.length == 1) {
41851 dragData.ddel = target.cloneNode(true); // the div element
41853 var div = document.createElement('div'); // create the multi element drag "ghost"
41854 div.className = 'multi-proxy';
41855 for (var i = 0, len = selNodes.length; i < len; i++) {
41856 div.appendChild(selNodes[i].cloneNode(true));
41858 dragData.ddel = div;
41860 //console.log(dragData)
41861 //console.log(dragData.ddel.innerHTML)
41864 //console.log('nodragData')
41868 /** Specify to which ddGroup items in this DDView may be dragged. */
41869 setDraggable: function(ddGroup) {
41870 if (ddGroup instanceof Array) {
41871 Roo.each(ddGroup, this.setDraggable, this);
41874 if (this.dragZone) {
41875 this.dragZone.addToGroup(ddGroup);
41877 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
41878 containerScroll: true,
41882 // Draggability implies selection. DragZone's mousedown selects the element.
41883 if (!this.multiSelect) { this.singleSelect = true; }
41885 // Wire the DragZone's handlers up to methods in *this*
41886 this.dragZone.getDragData = this.getDragData.createDelegate(this);
41890 /** Specify from which ddGroup this DDView accepts drops. */
41891 setDroppable: function(ddGroup) {
41892 if (ddGroup instanceof Array) {
41893 Roo.each(ddGroup, this.setDroppable, this);
41896 if (this.dropZone) {
41897 this.dropZone.addToGroup(ddGroup);
41899 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
41900 containerScroll: true,
41904 // Wire the DropZone's handlers up to methods in *this*
41905 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
41906 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
41907 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
41908 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
41909 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
41913 /** Decide whether to drop above or below a View node. */
41914 getDropPoint : function(e, n, dd){
41915 if (n == this.el.dom) { return "above"; }
41916 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
41917 var c = t + (b - t) / 2;
41918 var y = Roo.lib.Event.getPageY(e);
41926 onNodeEnter : function(n, dd, e, data){
41930 onNodeOver : function(n, dd, e, data){
41931 var pt = this.getDropPoint(e, n, dd);
41932 // set the insert point style on the target node
41933 var dragElClass = this.dropNotAllowed;
41936 if (pt == "above"){
41937 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
41938 targetElClass = "x-view-drag-insert-above";
41940 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
41941 targetElClass = "x-view-drag-insert-below";
41943 if (this.lastInsertClass != targetElClass){
41944 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
41945 this.lastInsertClass = targetElClass;
41948 return dragElClass;
41951 onNodeOut : function(n, dd, e, data){
41952 this.removeDropIndicators(n);
41955 onNodeDrop : function(n, dd, e, data){
41956 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
41959 var pt = this.getDropPoint(e, n, dd);
41960 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
41961 if (pt == "below") { insertAt++; }
41962 for (var i = 0; i < data.records.length; i++) {
41963 var r = data.records[i];
41964 var dup = this.store.getById(r.id);
41965 if (dup && (dd != this.dragZone)) {
41966 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
41969 this.store.insert(insertAt++, r.copy());
41971 data.source.isDirtyFlag = true;
41973 this.store.insert(insertAt++, r);
41975 this.isDirtyFlag = true;
41978 this.dragZone.cachedTarget = null;
41982 removeDropIndicators : function(n){
41984 Roo.fly(n).removeClass([
41985 "x-view-drag-insert-above",
41986 "x-view-drag-insert-below"]);
41987 this.lastInsertClass = "_noclass";
41992 * Utility method. Add a delete option to the DDView's context menu.
41993 * @param {String} imageUrl The URL of the "delete" icon image.
41995 setDeletable: function(imageUrl) {
41996 if (!this.singleSelect && !this.multiSelect) {
41997 this.singleSelect = true;
41999 var c = this.getContextMenu();
42000 this.contextMenu.on("itemclick", function(item) {
42003 this.remove(this.getSelectedIndexes());
42007 this.contextMenu.add({
42014 /** Return the context menu for this DDView. */
42015 getContextMenu: function() {
42016 if (!this.contextMenu) {
42017 // Create the View's context menu
42018 this.contextMenu = new Roo.menu.Menu({
42019 id: this.id + "-contextmenu"
42021 this.el.on("contextmenu", this.showContextMenu, this);
42023 return this.contextMenu;
42026 disableContextMenu: function() {
42027 if (this.contextMenu) {
42028 this.el.un("contextmenu", this.showContextMenu, this);
42032 showContextMenu: function(e, item) {
42033 item = this.findItemFromChild(e.getTarget());
42036 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
42037 this.contextMenu.showAt(e.getXY());
42042 * Remove {@link Roo.data.Record}s at the specified indices.
42043 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42045 remove: function(selectedIndices) {
42046 selectedIndices = [].concat(selectedIndices);
42047 for (var i = 0; i < selectedIndices.length; i++) {
42048 var rec = this.store.getAt(selectedIndices[i]);
42049 this.store.remove(rec);
42054 * Double click fires the event, but also, if this is draggable, and there is only one other
42055 * related DropZone, it transfers the selected node.
42057 onDblClick : function(e){
42058 var item = this.findItemFromChild(e.getTarget());
42060 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
42063 if (this.dragGroup) {
42064 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
42065 while (targets.indexOf(this.dropZone) > -1) {
42066 targets.remove(this.dropZone);
42068 if (targets.length == 1) {
42069 this.dragZone.cachedTarget = null;
42070 var el = Roo.get(targets[0].getEl());
42071 var box = el.getBox(true);
42072 targets[0].onNodeDrop(el.dom, {
42074 xy: [box.x, box.y + box.height - 1]
42075 }, null, this.getDragData(e));
42081 handleSelection: function(e) {
42082 this.dragZone.cachedTarget = null;
42083 var item = this.findItemFromChild(e.getTarget());
42085 this.clearSelections(true);
42088 if (item && (this.multiSelect || this.singleSelect)){
42089 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
42090 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
42091 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
42092 this.unselect(item);
42094 this.select(item, this.multiSelect && e.ctrlKey);
42095 this.lastSelection = item;
42100 onItemClick : function(item, index, e){
42101 if(this.fireEvent("beforeclick", this, index, item, e) === false){
42107 unselect : function(nodeInfo, suppressEvent){
42108 var node = this.getNode(nodeInfo);
42109 if(node && this.isSelected(node)){
42110 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
42111 Roo.fly(node).removeClass(this.selectedClass);
42112 this.selections.remove(node);
42113 if(!suppressEvent){
42114 this.fireEvent("selectionchange", this, this.selections);
42122 * Ext JS Library 1.1.1
42123 * Copyright(c) 2006-2007, Ext JS, LLC.
42125 * Originally Released Under LGPL - original licence link has changed is not relivant.
42128 * <script type="text/javascript">
42132 * @class Roo.LayoutManager
42133 * @extends Roo.util.Observable
42134 * Base class for layout managers.
42136 Roo.LayoutManager = function(container, config){
42137 Roo.LayoutManager.superclass.constructor.call(this);
42138 this.el = Roo.get(container);
42139 // ie scrollbar fix
42140 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
42141 document.body.scroll = "no";
42142 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
42143 this.el.position('relative');
42145 this.id = this.el.id;
42146 this.el.addClass("x-layout-container");
42147 /** false to disable window resize monitoring @type Boolean */
42148 this.monitorWindowResize = true;
42153 * Fires when a layout is performed.
42154 * @param {Roo.LayoutManager} this
42158 * @event regionresized
42159 * Fires when the user resizes a region.
42160 * @param {Roo.LayoutRegion} region The resized region
42161 * @param {Number} newSize The new size (width for east/west, height for north/south)
42163 "regionresized" : true,
42165 * @event regioncollapsed
42166 * Fires when a region is collapsed.
42167 * @param {Roo.LayoutRegion} region The collapsed region
42169 "regioncollapsed" : true,
42171 * @event regionexpanded
42172 * Fires when a region is expanded.
42173 * @param {Roo.LayoutRegion} region The expanded region
42175 "regionexpanded" : true
42177 this.updating = false;
42178 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
42181 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
42183 * Returns true if this layout is currently being updated
42184 * @return {Boolean}
42186 isUpdating : function(){
42187 return this.updating;
42191 * Suspend the LayoutManager from doing auto-layouts while
42192 * making multiple add or remove calls
42194 beginUpdate : function(){
42195 this.updating = true;
42199 * Restore auto-layouts and optionally disable the manager from performing a layout
42200 * @param {Boolean} noLayout true to disable a layout update
42202 endUpdate : function(noLayout){
42203 this.updating = false;
42209 layout: function(){
42213 onRegionResized : function(region, newSize){
42214 this.fireEvent("regionresized", region, newSize);
42218 onRegionCollapsed : function(region){
42219 this.fireEvent("regioncollapsed", region);
42222 onRegionExpanded : function(region){
42223 this.fireEvent("regionexpanded", region);
42227 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
42228 * performs box-model adjustments.
42229 * @return {Object} The size as an object {width: (the width), height: (the height)}
42231 getViewSize : function(){
42233 if(this.el.dom != document.body){
42234 size = this.el.getSize();
42236 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
42238 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
42239 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
42244 * Returns the Element this layout is bound to.
42245 * @return {Roo.Element}
42247 getEl : function(){
42252 * Returns the specified region.
42253 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
42254 * @return {Roo.LayoutRegion}
42256 getRegion : function(target){
42257 return this.regions[target.toLowerCase()];
42260 onWindowResize : function(){
42261 if(this.monitorWindowResize){
42267 * Ext JS Library 1.1.1
42268 * Copyright(c) 2006-2007, Ext JS, LLC.
42270 * Originally Released Under LGPL - original licence link has changed is not relivant.
42273 * <script type="text/javascript">
42276 * @class Roo.BorderLayout
42277 * @extends Roo.LayoutManager
42278 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
42279 * please see: <br><br>
42280 * <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>
42281 * <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>
42284 var layout = new Roo.BorderLayout(document.body, {
42318 preferredTabWidth: 150
42323 var CP = Roo.ContentPanel;
42325 layout.beginUpdate();
42326 layout.add("north", new CP("north", "North"));
42327 layout.add("south", new CP("south", {title: "South", closable: true}));
42328 layout.add("west", new CP("west", {title: "West"}));
42329 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
42330 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
42331 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
42332 layout.getRegion("center").showPanel("center1");
42333 layout.endUpdate();
42336 <b>The container the layout is rendered into can be either the body element or any other element.
42337 If it is not the body element, the container needs to either be an absolute positioned element,
42338 or you will need to add "position:relative" to the css of the container. You will also need to specify
42339 the container size if it is not the body element.</b>
42342 * Create a new BorderLayout
42343 * @param {String/HTMLElement/Element} container The container this layout is bound to
42344 * @param {Object} config Configuration options
42346 Roo.BorderLayout = function(container, config){
42347 config = config || {};
42348 Roo.BorderLayout.superclass.constructor.call(this, container, config);
42349 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
42350 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
42351 var target = this.factory.validRegions[i];
42352 if(config[target]){
42353 this.addRegion(target, config[target]);
42358 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
42360 * Creates and adds a new region if it doesn't already exist.
42361 * @param {String} target The target region key (north, south, east, west or center).
42362 * @param {Object} config The regions config object
42363 * @return {BorderLayoutRegion} The new region
42365 addRegion : function(target, config){
42366 if(!this.regions[target]){
42367 var r = this.factory.create(target, this, config);
42368 this.bindRegion(target, r);
42370 return this.regions[target];
42374 bindRegion : function(name, r){
42375 this.regions[name] = r;
42376 r.on("visibilitychange", this.layout, this);
42377 r.on("paneladded", this.layout, this);
42378 r.on("panelremoved", this.layout, this);
42379 r.on("invalidated", this.layout, this);
42380 r.on("resized", this.onRegionResized, this);
42381 r.on("collapsed", this.onRegionCollapsed, this);
42382 r.on("expanded", this.onRegionExpanded, this);
42386 * Performs a layout update.
42388 layout : function(){
42389 if(this.updating) return;
42390 var size = this.getViewSize();
42391 var w = size.width;
42392 var h = size.height;
42397 //var x = 0, y = 0;
42399 var rs = this.regions;
42400 var north = rs["north"];
42401 var south = rs["south"];
42402 var west = rs["west"];
42403 var east = rs["east"];
42404 var center = rs["center"];
42405 //if(this.hideOnLayout){ // not supported anymore
42406 //c.el.setStyle("display", "none");
42408 if(north && north.isVisible()){
42409 var b = north.getBox();
42410 var m = north.getMargins();
42411 b.width = w - (m.left+m.right);
42414 centerY = b.height + b.y + m.bottom;
42415 centerH -= centerY;
42416 north.updateBox(this.safeBox(b));
42418 if(south && south.isVisible()){
42419 var b = south.getBox();
42420 var m = south.getMargins();
42421 b.width = w - (m.left+m.right);
42423 var totalHeight = (b.height + m.top + m.bottom);
42424 b.y = h - totalHeight + m.top;
42425 centerH -= totalHeight;
42426 south.updateBox(this.safeBox(b));
42428 if(west && west.isVisible()){
42429 var b = west.getBox();
42430 var m = west.getMargins();
42431 b.height = centerH - (m.top+m.bottom);
42433 b.y = centerY + m.top;
42434 var totalWidth = (b.width + m.left + m.right);
42435 centerX += totalWidth;
42436 centerW -= totalWidth;
42437 west.updateBox(this.safeBox(b));
42439 if(east && east.isVisible()){
42440 var b = east.getBox();
42441 var m = east.getMargins();
42442 b.height = centerH - (m.top+m.bottom);
42443 var totalWidth = (b.width + m.left + m.right);
42444 b.x = w - totalWidth + m.left;
42445 b.y = centerY + m.top;
42446 centerW -= totalWidth;
42447 east.updateBox(this.safeBox(b));
42450 var m = center.getMargins();
42452 x: centerX + m.left,
42453 y: centerY + m.top,
42454 width: centerW - (m.left+m.right),
42455 height: centerH - (m.top+m.bottom)
42457 //if(this.hideOnLayout){
42458 //center.el.setStyle("display", "block");
42460 center.updateBox(this.safeBox(centerBox));
42463 this.fireEvent("layout", this);
42467 safeBox : function(box){
42468 box.width = Math.max(0, box.width);
42469 box.height = Math.max(0, box.height);
42474 * Adds a ContentPanel (or subclass) to this layout.
42475 * @param {String} target The target region key (north, south, east, west or center).
42476 * @param {Roo.ContentPanel} panel The panel to add
42477 * @return {Roo.ContentPanel} The added panel
42479 add : function(target, panel){
42481 target = target.toLowerCase();
42482 return this.regions[target].add(panel);
42486 * Remove a ContentPanel (or subclass) to this layout.
42487 * @param {String} target The target region key (north, south, east, west or center).
42488 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
42489 * @return {Roo.ContentPanel} The removed panel
42491 remove : function(target, panel){
42492 target = target.toLowerCase();
42493 return this.regions[target].remove(panel);
42497 * Searches all regions for a panel with the specified id
42498 * @param {String} panelId
42499 * @return {Roo.ContentPanel} The panel or null if it wasn't found
42501 findPanel : function(panelId){
42502 var rs = this.regions;
42503 for(var target in rs){
42504 if(typeof rs[target] != "function"){
42505 var p = rs[target].getPanel(panelId);
42515 * Searches all regions for a panel with the specified id and activates (shows) it.
42516 * @param {String/ContentPanel} panelId The panels id or the panel itself
42517 * @return {Roo.ContentPanel} The shown panel or null
42519 showPanel : function(panelId) {
42520 var rs = this.regions;
42521 for(var target in rs){
42522 var r = rs[target];
42523 if(typeof r != "function"){
42524 if(r.hasPanel(panelId)){
42525 return r.showPanel(panelId);
42533 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
42534 * @param {Roo.state.Provider} provider (optional) An alternate state provider
42536 restoreState : function(provider){
42538 provider = Roo.state.Manager;
42540 var sm = new Roo.LayoutStateManager();
42541 sm.init(this, provider);
42545 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
42546 * object should contain properties for each region to add ContentPanels to, and each property's value should be
42547 * a valid ContentPanel config object. Example:
42549 // Create the main layout
42550 var layout = new Roo.BorderLayout('main-ct', {
42561 // Create and add multiple ContentPanels at once via configs
42564 id: 'source-files',
42566 title:'Ext Source Files',
42579 * @param {Object} regions An object containing ContentPanel configs by region name
42581 batchAdd : function(regions){
42582 this.beginUpdate();
42583 for(var rname in regions){
42584 var lr = this.regions[rname];
42586 this.addTypedPanels(lr, regions[rname]);
42593 addTypedPanels : function(lr, ps){
42594 if(typeof ps == 'string'){
42595 lr.add(new Roo.ContentPanel(ps));
42597 else if(ps instanceof Array){
42598 for(var i =0, len = ps.length; i < len; i++){
42599 this.addTypedPanels(lr, ps[i]);
42602 else if(!ps.events){ // raw config?
42604 delete ps.el; // prevent conflict
42605 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
42607 else { // panel object assumed!
42612 * Adds a xtype elements to the layout.
42616 xtype : 'ContentPanel',
42623 xtype : 'NestedLayoutPanel',
42629 items : [ ... list of content panels or nested layout panels.. ]
42633 * @param {Object} cfg Xtype definition of item to add.
42635 addxtype : function(cfg)
42637 // basically accepts a pannel...
42638 // can accept a layout region..!?!?
42639 // console.log('BorderLayout add ' + cfg.xtype)
42641 if (!cfg.xtype.match(/Panel$/)) {
42645 var region = cfg.region;
42651 xitems = cfg.items;
42658 case 'ContentPanel': // ContentPanel (el, cfg)
42659 if(cfg.autoCreate) {
42660 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42662 var el = this.el.createChild();
42663 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
42666 this.add(region, ret);
42670 case 'TreePanel': // our new panel!
42671 cfg.el = this.el.createChild();
42672 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42673 this.add(region, ret);
42676 case 'NestedLayoutPanel':
42677 // create a new Layout (which is a Border Layout...
42678 var el = this.el.createChild();
42679 var clayout = cfg.layout;
42681 clayout.items = clayout.items || [];
42682 // replace this exitems with the clayout ones..
42683 xitems = clayout.items;
42686 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
42687 cfg.background = false;
42689 var layout = new Roo.BorderLayout(el, clayout);
42691 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
42692 //console.log('adding nested layout panel ' + cfg.toSource());
42693 this.add(region, ret);
42699 // needs grid and region
42701 //var el = this.getRegion(region).el.createChild();
42702 var el = this.el.createChild();
42703 // create the grid first...
42705 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
42707 if (region == 'center' && this.active ) {
42708 cfg.background = false;
42710 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
42712 this.add(region, ret);
42713 if (cfg.background) {
42714 ret.on('activate', function(gp) {
42715 if (!gp.grid.rendered) {
42728 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
42730 // GridPanel (grid, cfg)
42733 this.beginUpdate();
42735 Roo.each(xitems, function(i) {
42745 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
42746 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
42747 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
42748 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
42751 var CP = Roo.ContentPanel;
42753 var layout = Roo.BorderLayout.create({
42757 panels: [new CP("north", "North")]
42766 panels: [new CP("west", {title: "West"})]
42775 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
42784 panels: [new CP("south", {title: "South", closable: true})]
42791 preferredTabWidth: 150,
42793 new CP("center1", {title: "Close Me", closable: true}),
42794 new CP("center2", {title: "Center Panel", closable: false})
42799 layout.getRegion("center").showPanel("center1");
42804 Roo.BorderLayout.create = function(config, targetEl){
42805 var layout = new Roo.BorderLayout(targetEl || document.body, config);
42806 layout.beginUpdate();
42807 var regions = Roo.BorderLayout.RegionFactory.validRegions;
42808 for(var j = 0, jlen = regions.length; j < jlen; j++){
42809 var lr = regions[j];
42810 if(layout.regions[lr] && config[lr].panels){
42811 var r = layout.regions[lr];
42812 var ps = config[lr].panels;
42813 layout.addTypedPanels(r, ps);
42816 layout.endUpdate();
42821 Roo.BorderLayout.RegionFactory = {
42823 validRegions : ["north","south","east","west","center"],
42826 create : function(target, mgr, config){
42827 target = target.toLowerCase();
42828 if(config.lightweight || config.basic){
42829 return new Roo.BasicLayoutRegion(mgr, config, target);
42833 return new Roo.NorthLayoutRegion(mgr, config);
42835 return new Roo.SouthLayoutRegion(mgr, config);
42837 return new Roo.EastLayoutRegion(mgr, config);
42839 return new Roo.WestLayoutRegion(mgr, config);
42841 return new Roo.CenterLayoutRegion(mgr, config);
42843 throw 'Layout region "'+target+'" not supported.';
42847 * Ext JS Library 1.1.1
42848 * Copyright(c) 2006-2007, Ext JS, LLC.
42850 * Originally Released Under LGPL - original licence link has changed is not relivant.
42853 * <script type="text/javascript">
42857 * @class Roo.BasicLayoutRegion
42858 * @extends Roo.util.Observable
42859 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
42860 * and does not have a titlebar, tabs or any other features. All it does is size and position
42861 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
42863 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
42865 this.position = pos;
42868 * @scope Roo.BasicLayoutRegion
42872 * @event beforeremove
42873 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
42874 * @param {Roo.LayoutRegion} this
42875 * @param {Roo.ContentPanel} panel The panel
42876 * @param {Object} e The cancel event object
42878 "beforeremove" : true,
42880 * @event invalidated
42881 * Fires when the layout for this region is changed.
42882 * @param {Roo.LayoutRegion} this
42884 "invalidated" : true,
42886 * @event visibilitychange
42887 * Fires when this region is shown or hidden
42888 * @param {Roo.LayoutRegion} this
42889 * @param {Boolean} visibility true or false
42891 "visibilitychange" : true,
42893 * @event paneladded
42894 * Fires when a panel is added.
42895 * @param {Roo.LayoutRegion} this
42896 * @param {Roo.ContentPanel} panel The panel
42898 "paneladded" : true,
42900 * @event panelremoved
42901 * Fires when a panel is removed.
42902 * @param {Roo.LayoutRegion} this
42903 * @param {Roo.ContentPanel} panel The panel
42905 "panelremoved" : true,
42908 * Fires when this region is collapsed.
42909 * @param {Roo.LayoutRegion} this
42911 "collapsed" : true,
42914 * Fires when this region is expanded.
42915 * @param {Roo.LayoutRegion} this
42920 * Fires when this region is slid into view.
42921 * @param {Roo.LayoutRegion} this
42923 "slideshow" : true,
42926 * Fires when this region slides out of view.
42927 * @param {Roo.LayoutRegion} this
42929 "slidehide" : true,
42931 * @event panelactivated
42932 * Fires when a panel is activated.
42933 * @param {Roo.LayoutRegion} this
42934 * @param {Roo.ContentPanel} panel The activated panel
42936 "panelactivated" : true,
42939 * Fires when the user resizes this region.
42940 * @param {Roo.LayoutRegion} this
42941 * @param {Number} newSize The new size (width for east/west, height for north/south)
42945 /** A collection of panels in this region. @type Roo.util.MixedCollection */
42946 this.panels = new Roo.util.MixedCollection();
42947 this.panels.getKey = this.getPanelId.createDelegate(this);
42949 this.activePanel = null;
42950 // ensure listeners are added...
42952 if (config.listeners || config.events) {
42953 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
42954 listeners : config.listeners || {},
42955 events : config.events || {}
42959 if(skipConfig !== true){
42960 this.applyConfig(config);
42964 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
42965 getPanelId : function(p){
42969 applyConfig : function(config){
42970 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
42971 this.config = config;
42976 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
42977 * the width, for horizontal (north, south) the height.
42978 * @param {Number} newSize The new width or height
42980 resizeTo : function(newSize){
42981 var el = this.el ? this.el :
42982 (this.activePanel ? this.activePanel.getEl() : null);
42984 switch(this.position){
42987 el.setWidth(newSize);
42988 this.fireEvent("resized", this, newSize);
42992 el.setHeight(newSize);
42993 this.fireEvent("resized", this, newSize);
42999 getBox : function(){
43000 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
43003 getMargins : function(){
43004 return this.margins;
43007 updateBox : function(box){
43009 var el = this.activePanel.getEl();
43010 el.dom.style.left = box.x + "px";
43011 el.dom.style.top = box.y + "px";
43012 this.activePanel.setSize(box.width, box.height);
43016 * Returns the container element for this region.
43017 * @return {Roo.Element}
43019 getEl : function(){
43020 return this.activePanel;
43024 * Returns true if this region is currently visible.
43025 * @return {Boolean}
43027 isVisible : function(){
43028 return this.activePanel ? true : false;
43031 setActivePanel : function(panel){
43032 panel = this.getPanel(panel);
43033 if(this.activePanel && this.activePanel != panel){
43034 this.activePanel.setActiveState(false);
43035 this.activePanel.getEl().setLeftTop(-10000,-10000);
43037 this.activePanel = panel;
43038 panel.setActiveState(true);
43040 panel.setSize(this.box.width, this.box.height);
43042 this.fireEvent("panelactivated", this, panel);
43043 this.fireEvent("invalidated");
43047 * Show the specified panel.
43048 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43049 * @return {Roo.ContentPanel} The shown panel or null
43051 showPanel : function(panel){
43052 if(panel = this.getPanel(panel)){
43053 this.setActivePanel(panel);
43059 * Get the active panel for this region.
43060 * @return {Roo.ContentPanel} The active panel or null
43062 getActivePanel : function(){
43063 return this.activePanel;
43067 * Add the passed ContentPanel(s)
43068 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43069 * @return {Roo.ContentPanel} The panel added (if only one was added)
43071 add : function(panel){
43072 if(arguments.length > 1){
43073 for(var i = 0, len = arguments.length; i < len; i++) {
43074 this.add(arguments[i]);
43078 if(this.hasPanel(panel)){
43079 this.showPanel(panel);
43082 var el = panel.getEl();
43083 if(el.dom.parentNode != this.mgr.el.dom){
43084 this.mgr.el.dom.appendChild(el.dom);
43086 if(panel.setRegion){
43087 panel.setRegion(this);
43089 this.panels.add(panel);
43090 el.setStyle("position", "absolute");
43091 if(!panel.background){
43092 this.setActivePanel(panel);
43093 if(this.config.initialSize && this.panels.getCount()==1){
43094 this.resizeTo(this.config.initialSize);
43097 this.fireEvent("paneladded", this, panel);
43102 * Returns true if the panel is in this region.
43103 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43104 * @return {Boolean}
43106 hasPanel : function(panel){
43107 if(typeof panel == "object"){ // must be panel obj
43108 panel = panel.getId();
43110 return this.getPanel(panel) ? true : false;
43114 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43115 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43116 * @param {Boolean} preservePanel Overrides the config preservePanel option
43117 * @return {Roo.ContentPanel} The panel that was removed
43119 remove : function(panel, preservePanel){
43120 panel = this.getPanel(panel);
43125 this.fireEvent("beforeremove", this, panel, e);
43126 if(e.cancel === true){
43129 var panelId = panel.getId();
43130 this.panels.removeKey(panelId);
43135 * Returns the panel specified or null if it's not in this region.
43136 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43137 * @return {Roo.ContentPanel}
43139 getPanel : function(id){
43140 if(typeof id == "object"){ // must be panel obj
43143 return this.panels.get(id);
43147 * Returns this regions position (north/south/east/west/center).
43150 getPosition: function(){
43151 return this.position;
43155 * Ext JS Library 1.1.1
43156 * Copyright(c) 2006-2007, Ext JS, LLC.
43158 * Originally Released Under LGPL - original licence link has changed is not relivant.
43161 * <script type="text/javascript">
43165 * @class Roo.LayoutRegion
43166 * @extends Roo.BasicLayoutRegion
43167 * This class represents a region in a layout manager.
43168 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
43169 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
43170 * @cfg {Boolean} floatable False to disable floating (defaults to true)
43171 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
43172 * @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})
43173 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
43174 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
43175 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
43176 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
43177 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
43178 * @cfg {String} title The title for the region (overrides panel titles)
43179 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
43180 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
43181 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
43182 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
43183 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
43184 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
43185 * the space available, similar to FireFox 1.5 tabs (defaults to false)
43186 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
43187 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
43188 * @cfg {Boolean} showPin True to show a pin button
43189 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
43190 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
43191 * @cfg {Boolean} disableTabTips True to disable tab tooltips
43192 * @cfg {Number} width For East/West panels
43193 * @cfg {Number} height For North/South panels
43194 * @cfg {Boolean} split To show the splitter
43196 Roo.LayoutRegion = function(mgr, config, pos){
43197 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
43198 var dh = Roo.DomHelper;
43199 /** This region's container element
43200 * @type Roo.Element */
43201 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
43202 /** This region's title element
43203 * @type Roo.Element */
43205 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
43206 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
43207 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
43209 this.titleEl.enableDisplayMode();
43210 /** This region's title text element
43211 * @type HTMLElement */
43212 this.titleTextEl = this.titleEl.dom.firstChild;
43213 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
43214 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
43215 this.closeBtn.enableDisplayMode();
43216 this.closeBtn.on("click", this.closeClicked, this);
43217 this.closeBtn.hide();
43219 this.createBody(config);
43220 this.visible = true;
43221 this.collapsed = false;
43223 if(config.hideWhenEmpty){
43225 this.on("paneladded", this.validateVisibility, this);
43226 this.on("panelremoved", this.validateVisibility, this);
43228 this.applyConfig(config);
43231 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
43233 createBody : function(){
43234 /** This region's body element
43235 * @type Roo.Element */
43236 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
43239 applyConfig : function(c){
43240 if(c.collapsible && this.position != "center" && !this.collapsedEl){
43241 var dh = Roo.DomHelper;
43242 if(c.titlebar !== false){
43243 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
43244 this.collapseBtn.on("click", this.collapse, this);
43245 this.collapseBtn.enableDisplayMode();
43247 if(c.showPin === true || this.showPin){
43248 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
43249 this.stickBtn.enableDisplayMode();
43250 this.stickBtn.on("click", this.expand, this);
43251 this.stickBtn.hide();
43254 /** This region's collapsed element
43255 * @type Roo.Element */
43256 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
43257 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
43259 if(c.floatable !== false){
43260 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
43261 this.collapsedEl.on("click", this.collapseClick, this);
43264 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
43265 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
43266 id: "message", unselectable: "on", style:{"float":"left"}});
43267 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
43269 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
43270 this.expandBtn.on("click", this.expand, this);
43272 if(this.collapseBtn){
43273 this.collapseBtn.setVisible(c.collapsible == true);
43275 this.cmargins = c.cmargins || this.cmargins ||
43276 (this.position == "west" || this.position == "east" ?
43277 {top: 0, left: 2, right:2, bottom: 0} :
43278 {top: 2, left: 0, right:0, bottom: 2});
43279 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43280 this.bottomTabs = c.tabPosition != "top";
43281 this.autoScroll = c.autoScroll || false;
43282 if(this.autoScroll){
43283 this.bodyEl.setStyle("overflow", "auto");
43285 this.bodyEl.setStyle("overflow", "hidden");
43287 //if(c.titlebar !== false){
43288 if((!c.titlebar && !c.title) || c.titlebar === false){
43289 this.titleEl.hide();
43291 this.titleEl.show();
43293 this.titleTextEl.innerHTML = c.title;
43297 this.duration = c.duration || .30;
43298 this.slideDuration = c.slideDuration || .45;
43301 this.collapse(true);
43308 * Returns true if this region is currently visible.
43309 * @return {Boolean}
43311 isVisible : function(){
43312 return this.visible;
43316 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
43317 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
43319 setCollapsedTitle : function(title){
43320 title = title || " ";
43321 if(this.collapsedTitleTextEl){
43322 this.collapsedTitleTextEl.innerHTML = title;
43326 getBox : function(){
43328 if(!this.collapsed){
43329 b = this.el.getBox(false, true);
43331 b = this.collapsedEl.getBox(false, true);
43336 getMargins : function(){
43337 return this.collapsed ? this.cmargins : this.margins;
43340 highlight : function(){
43341 this.el.addClass("x-layout-panel-dragover");
43344 unhighlight : function(){
43345 this.el.removeClass("x-layout-panel-dragover");
43348 updateBox : function(box){
43350 if(!this.collapsed){
43351 this.el.dom.style.left = box.x + "px";
43352 this.el.dom.style.top = box.y + "px";
43353 this.updateBody(box.width, box.height);
43355 this.collapsedEl.dom.style.left = box.x + "px";
43356 this.collapsedEl.dom.style.top = box.y + "px";
43357 this.collapsedEl.setSize(box.width, box.height);
43360 this.tabs.autoSizeTabs();
43364 updateBody : function(w, h){
43366 this.el.setWidth(w);
43367 w -= this.el.getBorderWidth("rl");
43368 if(this.config.adjustments){
43369 w += this.config.adjustments[0];
43373 this.el.setHeight(h);
43374 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
43375 h -= this.el.getBorderWidth("tb");
43376 if(this.config.adjustments){
43377 h += this.config.adjustments[1];
43379 this.bodyEl.setHeight(h);
43381 h = this.tabs.syncHeight(h);
43384 if(this.panelSize){
43385 w = w !== null ? w : this.panelSize.width;
43386 h = h !== null ? h : this.panelSize.height;
43388 if(this.activePanel){
43389 var el = this.activePanel.getEl();
43390 w = w !== null ? w : el.getWidth();
43391 h = h !== null ? h : el.getHeight();
43392 this.panelSize = {width: w, height: h};
43393 this.activePanel.setSize(w, h);
43395 if(Roo.isIE && this.tabs){
43396 this.tabs.el.repaint();
43401 * Returns the container element for this region.
43402 * @return {Roo.Element}
43404 getEl : function(){
43409 * Hides this region.
43412 if(!this.collapsed){
43413 this.el.dom.style.left = "-2000px";
43416 this.collapsedEl.dom.style.left = "-2000px";
43417 this.collapsedEl.hide();
43419 this.visible = false;
43420 this.fireEvent("visibilitychange", this, false);
43424 * Shows this region if it was previously hidden.
43427 if(!this.collapsed){
43430 this.collapsedEl.show();
43432 this.visible = true;
43433 this.fireEvent("visibilitychange", this, true);
43436 closeClicked : function(){
43437 if(this.activePanel){
43438 this.remove(this.activePanel);
43442 collapseClick : function(e){
43444 e.stopPropagation();
43447 e.stopPropagation();
43453 * Collapses this region.
43454 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
43456 collapse : function(skipAnim){
43457 if(this.collapsed) return;
43458 this.collapsed = true;
43460 this.split.el.hide();
43462 if(this.config.animate && skipAnim !== true){
43463 this.fireEvent("invalidated", this);
43464 this.animateCollapse();
43466 this.el.setLocation(-20000,-20000);
43468 this.collapsedEl.show();
43469 this.fireEvent("collapsed", this);
43470 this.fireEvent("invalidated", this);
43474 animateCollapse : function(){
43479 * Expands this region if it was previously collapsed.
43480 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
43481 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
43483 expand : function(e, skipAnim){
43484 if(e) e.stopPropagation();
43485 if(!this.collapsed || this.el.hasActiveFx()) return;
43487 this.afterSlideIn();
43490 this.collapsed = false;
43491 if(this.config.animate && skipAnim !== true){
43492 this.animateExpand();
43496 this.split.el.show();
43498 this.collapsedEl.setLocation(-2000,-2000);
43499 this.collapsedEl.hide();
43500 this.fireEvent("invalidated", this);
43501 this.fireEvent("expanded", this);
43505 animateExpand : function(){
43509 initTabs : function(){
43510 this.bodyEl.setStyle("overflow", "hidden");
43511 var ts = new Roo.TabPanel(this.bodyEl.dom, {
43512 tabPosition: this.bottomTabs ? 'bottom' : 'top',
43513 disableTooltips: this.config.disableTabTips
43515 if(this.config.hideTabs){
43516 ts.stripWrap.setDisplayed(false);
43519 ts.resizeTabs = this.config.resizeTabs === true;
43520 ts.minTabWidth = this.config.minTabWidth || 40;
43521 ts.maxTabWidth = this.config.maxTabWidth || 250;
43522 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
43523 ts.monitorResize = false;
43524 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43525 ts.bodyEl.addClass('x-layout-tabs-body');
43526 this.panels.each(this.initPanelAsTab, this);
43529 initPanelAsTab : function(panel){
43530 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
43531 this.config.closeOnTab && panel.isClosable());
43532 if(panel.tabTip !== undefined){
43533 ti.setTooltip(panel.tabTip);
43535 ti.on("activate", function(){
43536 this.setActivePanel(panel);
43538 if(this.config.closeOnTab){
43539 ti.on("beforeclose", function(t, e){
43541 this.remove(panel);
43547 updatePanelTitle : function(panel, title){
43548 if(this.activePanel == panel){
43549 this.updateTitle(title);
43552 var ti = this.tabs.getTab(panel.getEl().id);
43554 if(panel.tabTip !== undefined){
43555 ti.setTooltip(panel.tabTip);
43560 updateTitle : function(title){
43561 if(this.titleTextEl && !this.config.title){
43562 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
43566 setActivePanel : function(panel){
43567 panel = this.getPanel(panel);
43568 if(this.activePanel && this.activePanel != panel){
43569 this.activePanel.setActiveState(false);
43571 this.activePanel = panel;
43572 panel.setActiveState(true);
43573 if(this.panelSize){
43574 panel.setSize(this.panelSize.width, this.panelSize.height);
43577 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
43579 this.updateTitle(panel.getTitle());
43581 this.fireEvent("invalidated", this);
43583 this.fireEvent("panelactivated", this, panel);
43587 * Shows the specified panel.
43588 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
43589 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
43591 showPanel : function(panel){
43592 if(panel = this.getPanel(panel)){
43594 var tab = this.tabs.getTab(panel.getEl().id);
43595 if(tab.isHidden()){
43596 this.tabs.unhideTab(tab.id);
43600 this.setActivePanel(panel);
43607 * Get the active panel for this region.
43608 * @return {Roo.ContentPanel} The active panel or null
43610 getActivePanel : function(){
43611 return this.activePanel;
43614 validateVisibility : function(){
43615 if(this.panels.getCount() < 1){
43616 this.updateTitle(" ");
43617 this.closeBtn.hide();
43620 if(!this.isVisible()){
43627 * Adds the passed ContentPanel(s) to this region.
43628 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43629 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
43631 add : function(panel){
43632 if(arguments.length > 1){
43633 for(var i = 0, len = arguments.length; i < len; i++) {
43634 this.add(arguments[i]);
43638 if(this.hasPanel(panel)){
43639 this.showPanel(panel);
43642 panel.setRegion(this);
43643 this.panels.add(panel);
43644 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
43645 this.bodyEl.dom.appendChild(panel.getEl().dom);
43646 if(panel.background !== true){
43647 this.setActivePanel(panel);
43649 this.fireEvent("paneladded", this, panel);
43655 this.initPanelAsTab(panel);
43657 if(panel.background !== true){
43658 this.tabs.activate(panel.getEl().id);
43660 this.fireEvent("paneladded", this, panel);
43665 * Hides the tab for the specified panel.
43666 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43668 hidePanel : function(panel){
43669 if(this.tabs && (panel = this.getPanel(panel))){
43670 this.tabs.hideTab(panel.getEl().id);
43675 * Unhides the tab for a previously hidden panel.
43676 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43678 unhidePanel : function(panel){
43679 if(this.tabs && (panel = this.getPanel(panel))){
43680 this.tabs.unhideTab(panel.getEl().id);
43684 clearPanels : function(){
43685 while(this.panels.getCount() > 0){
43686 this.remove(this.panels.first());
43691 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43692 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43693 * @param {Boolean} preservePanel Overrides the config preservePanel option
43694 * @return {Roo.ContentPanel} The panel that was removed
43696 remove : function(panel, preservePanel){
43697 panel = this.getPanel(panel);
43702 this.fireEvent("beforeremove", this, panel, e);
43703 if(e.cancel === true){
43706 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
43707 var panelId = panel.getId();
43708 this.panels.removeKey(panelId);
43710 document.body.appendChild(panel.getEl().dom);
43713 this.tabs.removeTab(panel.getEl().id);
43714 }else if (!preservePanel){
43715 this.bodyEl.dom.removeChild(panel.getEl().dom);
43717 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
43718 var p = this.panels.first();
43719 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
43720 tempEl.appendChild(p.getEl().dom);
43721 this.bodyEl.update("");
43722 this.bodyEl.dom.appendChild(p.getEl().dom);
43724 this.updateTitle(p.getTitle());
43726 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43727 this.setActivePanel(p);
43729 panel.setRegion(null);
43730 if(this.activePanel == panel){
43731 this.activePanel = null;
43733 if(this.config.autoDestroy !== false && preservePanel !== true){
43734 try{panel.destroy();}catch(e){}
43736 this.fireEvent("panelremoved", this, panel);
43741 * Returns the TabPanel component used by this region
43742 * @return {Roo.TabPanel}
43744 getTabs : function(){
43748 createTool : function(parentEl, className){
43749 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
43750 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
43751 btn.addClassOnOver("x-layout-tools-button-over");
43756 * Ext JS Library 1.1.1
43757 * Copyright(c) 2006-2007, Ext JS, LLC.
43759 * Originally Released Under LGPL - original licence link has changed is not relivant.
43762 * <script type="text/javascript">
43768 * @class Roo.SplitLayoutRegion
43769 * @extends Roo.LayoutRegion
43770 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
43772 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
43773 this.cursor = cursor;
43774 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
43777 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
43778 splitTip : "Drag to resize.",
43779 collapsibleSplitTip : "Drag to resize. Double click to hide.",
43780 useSplitTips : false,
43782 applyConfig : function(config){
43783 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
43786 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
43787 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
43788 /** The SplitBar for this region
43789 * @type Roo.SplitBar */
43790 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
43791 this.split.on("moved", this.onSplitMove, this);
43792 this.split.useShim = config.useShim === true;
43793 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
43794 if(this.useSplitTips){
43795 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
43797 if(config.collapsible){
43798 this.split.el.on("dblclick", this.collapse, this);
43801 if(typeof config.minSize != "undefined"){
43802 this.split.minSize = config.minSize;
43804 if(typeof config.maxSize != "undefined"){
43805 this.split.maxSize = config.maxSize;
43807 if(config.hideWhenEmpty || config.hidden || config.collapsed){
43808 this.hideSplitter();
43813 getHMaxSize : function(){
43814 var cmax = this.config.maxSize || 10000;
43815 var center = this.mgr.getRegion("center");
43816 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
43819 getVMaxSize : function(){
43820 var cmax = this.config.maxSize || 10000;
43821 var center = this.mgr.getRegion("center");
43822 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
43825 onSplitMove : function(split, newSize){
43826 this.fireEvent("resized", this, newSize);
43830 * Returns the {@link Roo.SplitBar} for this region.
43831 * @return {Roo.SplitBar}
43833 getSplitBar : function(){
43838 this.hideSplitter();
43839 Roo.SplitLayoutRegion.superclass.hide.call(this);
43842 hideSplitter : function(){
43844 this.split.el.setLocation(-2000,-2000);
43845 this.split.el.hide();
43851 this.split.el.show();
43853 Roo.SplitLayoutRegion.superclass.show.call(this);
43856 beforeSlide: function(){
43857 if(Roo.isGecko){// firefox overflow auto bug workaround
43858 this.bodyEl.clip();
43859 if(this.tabs) this.tabs.bodyEl.clip();
43860 if(this.activePanel){
43861 this.activePanel.getEl().clip();
43863 if(this.activePanel.beforeSlide){
43864 this.activePanel.beforeSlide();
43870 afterSlide : function(){
43871 if(Roo.isGecko){// firefox overflow auto bug workaround
43872 this.bodyEl.unclip();
43873 if(this.tabs) this.tabs.bodyEl.unclip();
43874 if(this.activePanel){
43875 this.activePanel.getEl().unclip();
43876 if(this.activePanel.afterSlide){
43877 this.activePanel.afterSlide();
43883 initAutoHide : function(){
43884 if(this.autoHide !== false){
43885 if(!this.autoHideHd){
43886 var st = new Roo.util.DelayedTask(this.slideIn, this);
43887 this.autoHideHd = {
43888 "mouseout": function(e){
43889 if(!e.within(this.el, true)){
43893 "mouseover" : function(e){
43899 this.el.on(this.autoHideHd);
43903 clearAutoHide : function(){
43904 if(this.autoHide !== false){
43905 this.el.un("mouseout", this.autoHideHd.mouseout);
43906 this.el.un("mouseover", this.autoHideHd.mouseover);
43910 clearMonitor : function(){
43911 Roo.get(document).un("click", this.slideInIf, this);
43914 // these names are backwards but not changed for compat
43915 slideOut : function(){
43916 if(this.isSlid || this.el.hasActiveFx()){
43919 this.isSlid = true;
43920 if(this.collapseBtn){
43921 this.collapseBtn.hide();
43923 this.closeBtnState = this.closeBtn.getStyle('display');
43924 this.closeBtn.hide();
43926 this.stickBtn.show();
43929 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
43930 this.beforeSlide();
43931 this.el.setStyle("z-index", 10001);
43932 this.el.slideIn(this.getSlideAnchor(), {
43933 callback: function(){
43935 this.initAutoHide();
43936 Roo.get(document).on("click", this.slideInIf, this);
43937 this.fireEvent("slideshow", this);
43944 afterSlideIn : function(){
43945 this.clearAutoHide();
43946 this.isSlid = false;
43947 this.clearMonitor();
43948 this.el.setStyle("z-index", "");
43949 if(this.collapseBtn){
43950 this.collapseBtn.show();
43952 this.closeBtn.setStyle('display', this.closeBtnState);
43954 this.stickBtn.hide();
43956 this.fireEvent("slidehide", this);
43959 slideIn : function(cb){
43960 if(!this.isSlid || this.el.hasActiveFx()){
43964 this.isSlid = false;
43965 this.beforeSlide();
43966 this.el.slideOut(this.getSlideAnchor(), {
43967 callback: function(){
43968 this.el.setLeftTop(-10000, -10000);
43970 this.afterSlideIn();
43978 slideInIf : function(e){
43979 if(!e.within(this.el)){
43984 animateCollapse : function(){
43985 this.beforeSlide();
43986 this.el.setStyle("z-index", 20000);
43987 var anchor = this.getSlideAnchor();
43988 this.el.slideOut(anchor, {
43989 callback : function(){
43990 this.el.setStyle("z-index", "");
43991 this.collapsedEl.slideIn(anchor, {duration:.3});
43993 this.el.setLocation(-10000,-10000);
43995 this.fireEvent("collapsed", this);
44002 animateExpand : function(){
44003 this.beforeSlide();
44004 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
44005 this.el.setStyle("z-index", 20000);
44006 this.collapsedEl.hide({
44009 this.el.slideIn(this.getSlideAnchor(), {
44010 callback : function(){
44011 this.el.setStyle("z-index", "");
44014 this.split.el.show();
44016 this.fireEvent("invalidated", this);
44017 this.fireEvent("expanded", this);
44045 getAnchor : function(){
44046 return this.anchors[this.position];
44049 getCollapseAnchor : function(){
44050 return this.canchors[this.position];
44053 getSlideAnchor : function(){
44054 return this.sanchors[this.position];
44057 getAlignAdj : function(){
44058 var cm = this.cmargins;
44059 switch(this.position){
44075 getExpandAdj : function(){
44076 var c = this.collapsedEl, cm = this.cmargins;
44077 switch(this.position){
44079 return [-(cm.right+c.getWidth()+cm.left), 0];
44082 return [cm.right+c.getWidth()+cm.left, 0];
44085 return [0, -(cm.top+cm.bottom+c.getHeight())];
44088 return [0, cm.top+cm.bottom+c.getHeight()];
44094 * Ext JS Library 1.1.1
44095 * Copyright(c) 2006-2007, Ext JS, LLC.
44097 * Originally Released Under LGPL - original licence link has changed is not relivant.
44100 * <script type="text/javascript">
44103 * These classes are private internal classes
44105 Roo.CenterLayoutRegion = function(mgr, config){
44106 Roo.LayoutRegion.call(this, mgr, config, "center");
44107 this.visible = true;
44108 this.minWidth = config.minWidth || 20;
44109 this.minHeight = config.minHeight || 20;
44112 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
44114 // center panel can't be hidden
44118 // center panel can't be hidden
44121 getMinWidth: function(){
44122 return this.minWidth;
44125 getMinHeight: function(){
44126 return this.minHeight;
44131 Roo.NorthLayoutRegion = function(mgr, config){
44132 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
44134 this.split.placement = Roo.SplitBar.TOP;
44135 this.split.orientation = Roo.SplitBar.VERTICAL;
44136 this.split.el.addClass("x-layout-split-v");
44138 var size = config.initialSize || config.height;
44139 if(typeof size != "undefined"){
44140 this.el.setHeight(size);
44143 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
44144 orientation: Roo.SplitBar.VERTICAL,
44145 getBox : function(){
44146 if(this.collapsed){
44147 return this.collapsedEl.getBox();
44149 var box = this.el.getBox();
44151 box.height += this.split.el.getHeight();
44156 updateBox : function(box){
44157 if(this.split && !this.collapsed){
44158 box.height -= this.split.el.getHeight();
44159 this.split.el.setLeft(box.x);
44160 this.split.el.setTop(box.y+box.height);
44161 this.split.el.setWidth(box.width);
44163 if(this.collapsed){
44164 this.updateBody(box.width, null);
44166 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44170 Roo.SouthLayoutRegion = function(mgr, config){
44171 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
44173 this.split.placement = Roo.SplitBar.BOTTOM;
44174 this.split.orientation = Roo.SplitBar.VERTICAL;
44175 this.split.el.addClass("x-layout-split-v");
44177 var size = config.initialSize || config.height;
44178 if(typeof size != "undefined"){
44179 this.el.setHeight(size);
44182 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
44183 orientation: Roo.SplitBar.VERTICAL,
44184 getBox : function(){
44185 if(this.collapsed){
44186 return this.collapsedEl.getBox();
44188 var box = this.el.getBox();
44190 var sh = this.split.el.getHeight();
44197 updateBox : function(box){
44198 if(this.split && !this.collapsed){
44199 var sh = this.split.el.getHeight();
44202 this.split.el.setLeft(box.x);
44203 this.split.el.setTop(box.y-sh);
44204 this.split.el.setWidth(box.width);
44206 if(this.collapsed){
44207 this.updateBody(box.width, null);
44209 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44213 Roo.EastLayoutRegion = function(mgr, config){
44214 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
44216 this.split.placement = Roo.SplitBar.RIGHT;
44217 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44218 this.split.el.addClass("x-layout-split-h");
44220 var size = config.initialSize || config.width;
44221 if(typeof size != "undefined"){
44222 this.el.setWidth(size);
44225 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
44226 orientation: Roo.SplitBar.HORIZONTAL,
44227 getBox : function(){
44228 if(this.collapsed){
44229 return this.collapsedEl.getBox();
44231 var box = this.el.getBox();
44233 var sw = this.split.el.getWidth();
44240 updateBox : function(box){
44241 if(this.split && !this.collapsed){
44242 var sw = this.split.el.getWidth();
44244 this.split.el.setLeft(box.x);
44245 this.split.el.setTop(box.y);
44246 this.split.el.setHeight(box.height);
44249 if(this.collapsed){
44250 this.updateBody(null, box.height);
44252 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44256 Roo.WestLayoutRegion = function(mgr, config){
44257 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
44259 this.split.placement = Roo.SplitBar.LEFT;
44260 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44261 this.split.el.addClass("x-layout-split-h");
44263 var size = config.initialSize || config.width;
44264 if(typeof size != "undefined"){
44265 this.el.setWidth(size);
44268 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
44269 orientation: Roo.SplitBar.HORIZONTAL,
44270 getBox : function(){
44271 if(this.collapsed){
44272 return this.collapsedEl.getBox();
44274 var box = this.el.getBox();
44276 box.width += this.split.el.getWidth();
44281 updateBox : function(box){
44282 if(this.split && !this.collapsed){
44283 var sw = this.split.el.getWidth();
44285 this.split.el.setLeft(box.x+box.width);
44286 this.split.el.setTop(box.y);
44287 this.split.el.setHeight(box.height);
44289 if(this.collapsed){
44290 this.updateBody(null, box.height);
44292 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44297 * Ext JS Library 1.1.1
44298 * Copyright(c) 2006-2007, Ext JS, LLC.
44300 * Originally Released Under LGPL - original licence link has changed is not relivant.
44303 * <script type="text/javascript">
44308 * Private internal class for reading and applying state
44310 Roo.LayoutStateManager = function(layout){
44311 // default empty state
44320 Roo.LayoutStateManager.prototype = {
44321 init : function(layout, provider){
44322 this.provider = provider;
44323 var state = provider.get(layout.id+"-layout-state");
44325 var wasUpdating = layout.isUpdating();
44327 layout.beginUpdate();
44329 for(var key in state){
44330 if(typeof state[key] != "function"){
44331 var rstate = state[key];
44332 var r = layout.getRegion(key);
44335 r.resizeTo(rstate.size);
44337 if(rstate.collapsed == true){
44340 r.expand(null, true);
44346 layout.endUpdate();
44348 this.state = state;
44350 this.layout = layout;
44351 layout.on("regionresized", this.onRegionResized, this);
44352 layout.on("regioncollapsed", this.onRegionCollapsed, this);
44353 layout.on("regionexpanded", this.onRegionExpanded, this);
44356 storeState : function(){
44357 this.provider.set(this.layout.id+"-layout-state", this.state);
44360 onRegionResized : function(region, newSize){
44361 this.state[region.getPosition()].size = newSize;
44365 onRegionCollapsed : function(region){
44366 this.state[region.getPosition()].collapsed = true;
44370 onRegionExpanded : function(region){
44371 this.state[region.getPosition()].collapsed = false;
44376 * Ext JS Library 1.1.1
44377 * Copyright(c) 2006-2007, Ext JS, LLC.
44379 * Originally Released Under LGPL - original licence link has changed is not relivant.
44382 * <script type="text/javascript">
44385 * @class Roo.ContentPanel
44386 * @extends Roo.util.Observable
44387 * A basic ContentPanel element.
44388 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
44389 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
44390 * @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
44391 * @cfg {Boolean} closable True if the panel can be closed/removed
44392 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
44393 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
44394 * @cfg {Toolbar} toolbar A toolbar for this panel
44395 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
44396 * @cfg {String} title The title for this panel
44397 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
44398 * @cfg {String} url Calls {@link #setUrl} with this value
44399 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
44400 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
44402 * Create a new ContentPanel.
44403 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
44404 * @param {String/Object} config A string to set only the title or a config object
44405 * @param {String} content (optional) Set the HTML content for this panel
44406 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
44408 Roo.ContentPanel = function(el, config, content){
44412 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
44416 if (config && config.parentLayout) {
44417 el = config.parentLayout.el.createChild();
44420 if(el.autoCreate){ // xtype is available if this is called from factory
44424 this.el = Roo.get(el);
44425 if(!this.el && config && config.autoCreate){
44426 if(typeof config.autoCreate == "object"){
44427 if(!config.autoCreate.id){
44428 config.autoCreate.id = config.id||el;
44430 this.el = Roo.DomHelper.append(document.body,
44431 config.autoCreate, true);
44433 this.el = Roo.DomHelper.append(document.body,
44434 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
44437 this.closable = false;
44438 this.loaded = false;
44439 this.active = false;
44440 if(typeof config == "string"){
44441 this.title = config;
44443 Roo.apply(this, config);
44446 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
44447 this.wrapEl = this.el.wrap();
44448 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
44455 this.resizeEl = Roo.get(this.resizeEl, true);
44457 this.resizeEl = this.el;
44462 * Fires when this panel is activated.
44463 * @param {Roo.ContentPanel} this
44467 * @event deactivate
44468 * Fires when this panel is activated.
44469 * @param {Roo.ContentPanel} this
44471 "deactivate" : true,
44475 * Fires when this panel is resized if fitToFrame is true.
44476 * @param {Roo.ContentPanel} this
44477 * @param {Number} width The width after any component adjustments
44478 * @param {Number} height The height after any component adjustments
44482 if(this.autoScroll){
44483 this.resizeEl.setStyle("overflow", "auto");
44485 content = content || this.content;
44487 this.setContent(content);
44489 if(config && config.url){
44490 this.setUrl(this.url, this.params, this.loadOnce);
44495 Roo.ContentPanel.superclass.constructor.call(this);
44498 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
44500 setRegion : function(region){
44501 this.region = region;
44503 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
44505 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
44510 * Returns the toolbar for this Panel if one was configured.
44511 * @return {Roo.Toolbar}
44513 getToolbar : function(){
44514 return this.toolbar;
44517 setActiveState : function(active){
44518 this.active = active;
44520 this.fireEvent("deactivate", this);
44522 this.fireEvent("activate", this);
44526 * Updates this panel's element
44527 * @param {String} content The new content
44528 * @param {Boolean} loadScripts (optional) true to look for and process scripts
44530 setContent : function(content, loadScripts){
44531 this.el.update(content, loadScripts);
44534 ignoreResize : function(w, h){
44535 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
44538 this.lastSize = {width: w, height: h};
44543 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
44544 * @return {Roo.UpdateManager} The UpdateManager
44546 getUpdateManager : function(){
44547 return this.el.getUpdateManager();
44550 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
44551 * @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:
44554 url: "your-url.php",
44555 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
44556 callback: yourFunction,
44557 scope: yourObject, //(optional scope)
44560 text: "Loading...",
44565 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
44566 * 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.
44567 * @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}
44568 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
44569 * @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.
44570 * @return {Roo.ContentPanel} this
44573 var um = this.el.getUpdateManager();
44574 um.update.apply(um, arguments);
44580 * 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.
44581 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
44582 * @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)
44583 * @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)
44584 * @return {Roo.UpdateManager} The UpdateManager
44586 setUrl : function(url, params, loadOnce){
44587 if(this.refreshDelegate){
44588 this.removeListener("activate", this.refreshDelegate);
44590 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
44591 this.on("activate", this.refreshDelegate);
44592 return this.el.getUpdateManager();
44595 _handleRefresh : function(url, params, loadOnce){
44596 if(!loadOnce || !this.loaded){
44597 var updater = this.el.getUpdateManager();
44598 updater.update(url, params, this._setLoaded.createDelegate(this));
44602 _setLoaded : function(){
44603 this.loaded = true;
44607 * Returns this panel's id
44610 getId : function(){
44615 * Returns this panel's element - used by regiosn to add.
44616 * @return {Roo.Element}
44618 getEl : function(){
44619 return this.wrapEl || this.el;
44622 adjustForComponents : function(width, height){
44623 if(this.resizeEl != this.el){
44624 width -= this.el.getFrameWidth('lr');
44625 height -= this.el.getFrameWidth('tb');
44628 var te = this.toolbar.getEl();
44629 height -= te.getHeight();
44630 te.setWidth(width);
44632 if(this.adjustments){
44633 width += this.adjustments[0];
44634 height += this.adjustments[1];
44636 return {"width": width, "height": height};
44639 setSize : function(width, height){
44640 if(this.fitToFrame && !this.ignoreResize(width, height)){
44641 if(this.fitContainer && this.resizeEl != this.el){
44642 this.el.setSize(width, height);
44644 var size = this.adjustForComponents(width, height);
44645 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
44646 this.fireEvent('resize', this, size.width, size.height);
44651 * Returns this panel's title
44654 getTitle : function(){
44659 * Set this panel's title
44660 * @param {String} title
44662 setTitle : function(title){
44663 this.title = title;
44665 this.region.updatePanelTitle(this, title);
44670 * Returns true is this panel was configured to be closable
44671 * @return {Boolean}
44673 isClosable : function(){
44674 return this.closable;
44677 beforeSlide : function(){
44679 this.resizeEl.clip();
44682 afterSlide : function(){
44684 this.resizeEl.unclip();
44688 * Force a content refresh from the URL specified in the {@link #setUrl} method.
44689 * Will fail silently if the {@link #setUrl} method has not been called.
44690 * This does not activate the panel, just updates its content.
44692 refresh : function(){
44693 if(this.refreshDelegate){
44694 this.loaded = false;
44695 this.refreshDelegate();
44700 * Destroys this panel
44702 destroy : function(){
44703 this.el.removeAllListeners();
44704 var tempEl = document.createElement("span");
44705 tempEl.appendChild(this.el.dom);
44706 tempEl.innerHTML = "";
44712 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
44722 * @param {Object} cfg Xtype definition of item to add.
44725 addxtype : function(cfg) {
44727 if (cfg.xtype.match(/^Form$/)) {
44728 var el = this.el.createChild();
44730 this.form = new Roo.form.Form(cfg);
44733 if ( this.form.allItems.length) this.form.render(el.dom);
44736 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
44740 var ret = new Roo[cfg.xtype](cfg);
44741 ret.render(false, ''); // render blank..
44751 * @class Roo.GridPanel
44752 * @extends Roo.ContentPanel
44754 * Create a new GridPanel.
44755 * @param {Roo.grid.Grid} grid The grid for this panel
44756 * @param {String/Object} config A string to set only the panel's title, or a config object
44758 Roo.GridPanel = function(grid, config){
44761 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
44762 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
44764 this.wrapper.dom.appendChild(grid.getGridEl().dom);
44766 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
44769 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
44771 // xtype created footer. - not sure if will work as we normally have to render first..
44772 if (this.footer && !this.footer.el && this.footer.xtype) {
44774 this.footer.container = this.grid.getView().getFooterPanel(true);
44775 this.footer.dataSource = this.grid.dataSource;
44776 this.footer = Roo.factory(this.footer, Roo);
44780 grid.monitorWindowResize = false; // turn off autosizing
44781 grid.autoHeight = false;
44782 grid.autoWidth = false;
44784 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
44787 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
44788 getId : function(){
44789 return this.grid.id;
44793 * Returns the grid for this panel
44794 * @return {Roo.grid.Grid}
44796 getGrid : function(){
44800 setSize : function(width, height){
44801 if(!this.ignoreResize(width, height)){
44802 var grid = this.grid;
44803 var size = this.adjustForComponents(width, height);
44804 grid.getGridEl().setSize(size.width, size.height);
44809 beforeSlide : function(){
44810 this.grid.getView().scroller.clip();
44813 afterSlide : function(){
44814 this.grid.getView().scroller.unclip();
44817 destroy : function(){
44818 this.grid.destroy();
44820 Roo.GridPanel.superclass.destroy.call(this);
44826 * @class Roo.NestedLayoutPanel
44827 * @extends Roo.ContentPanel
44829 * Create a new NestedLayoutPanel.
44832 * @param {Roo.BorderLayout} layout The layout for this panel
44833 * @param {String/Object} config A string to set only the title or a config object
44835 Roo.NestedLayoutPanel = function(layout, config)
44837 // construct with only one argument..
44838 /* FIXME - implement nicer consturctors
44839 if (layout.layout) {
44841 layout = config.layout;
44842 delete config.layout;
44844 if (layout.xtype && !layout.getEl) {
44845 // then layout needs constructing..
44846 layout = Roo.factory(layout, Roo);
44850 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
44852 layout.monitorWindowResize = false; // turn off autosizing
44853 this.layout = layout;
44854 this.layout.getEl().addClass("x-layout-nested-layout");
44860 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
44862 setSize : function(width, height){
44863 if(!this.ignoreResize(width, height)){
44864 var size = this.adjustForComponents(width, height);
44865 var el = this.layout.getEl();
44866 el.setSize(size.width, size.height);
44867 var touch = el.dom.offsetWidth;
44868 this.layout.layout();
44869 // ie requires a double layout on the first pass
44870 if(Roo.isIE && !this.initialized){
44871 this.initialized = true;
44872 this.layout.layout();
44877 // activate all subpanels if not currently active..
44879 setActiveState : function(active){
44880 this.active = active;
44882 this.fireEvent("deactivate", this);
44886 this.fireEvent("activate", this);
44887 // not sure if this should happen before or after..
44888 if (!this.layout) {
44889 return; // should not happen..
44892 for (var r in this.layout.regions) {
44893 reg = this.layout.getRegion(r);
44894 if (reg.getActivePanel()) {
44895 //reg.showPanel(reg.getActivePanel()); // force it to activate..
44896 reg.setActivePanel(reg.getActivePanel());
44899 if (!reg.panels.length) {
44902 reg.showPanel(reg.getPanel(0));
44911 * Returns the nested BorderLayout for this panel
44912 * @return {Roo.BorderLayout}
44914 getLayout : function(){
44915 return this.layout;
44919 * Adds a xtype elements to the layout of the nested panel
44923 xtype : 'ContentPanel',
44930 xtype : 'NestedLayoutPanel',
44936 items : [ ... list of content panels or nested layout panels.. ]
44940 * @param {Object} cfg Xtype definition of item to add.
44942 addxtype : function(cfg) {
44943 return this.layout.addxtype(cfg);
44948 Roo.ScrollPanel = function(el, config, content){
44949 config = config || {};
44950 config.fitToFrame = true;
44951 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
44953 this.el.dom.style.overflow = "hidden";
44954 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
44955 this.el.removeClass("x-layout-inactive-content");
44956 this.el.on("mousewheel", this.onWheel, this);
44958 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
44959 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
44960 up.unselectable(); down.unselectable();
44961 up.on("click", this.scrollUp, this);
44962 down.on("click", this.scrollDown, this);
44963 up.addClassOnOver("x-scroller-btn-over");
44964 down.addClassOnOver("x-scroller-btn-over");
44965 up.addClassOnClick("x-scroller-btn-click");
44966 down.addClassOnClick("x-scroller-btn-click");
44967 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
44969 this.resizeEl = this.el;
44970 this.el = wrap; this.up = up; this.down = down;
44973 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
44975 wheelIncrement : 5,
44976 scrollUp : function(){
44977 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
44980 scrollDown : function(){
44981 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
44984 afterScroll : function(){
44985 var el = this.resizeEl;
44986 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
44987 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44988 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44991 setSize : function(){
44992 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
44993 this.afterScroll();
44996 onWheel : function(e){
44997 var d = e.getWheelDelta();
44998 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
44999 this.afterScroll();
45003 setContent : function(content, loadScripts){
45004 this.resizeEl.update(content, loadScripts);
45018 * @class Roo.TreePanel
45019 * @extends Roo.ContentPanel
45021 * Create a new TreePanel.
45022 * @param {String/Object} config A string to set only the panel's title, or a config object
45023 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
45025 Roo.TreePanel = function(config){
45026 var el = config.el;
45027 var tree = config.tree;
45028 delete config.tree;
45029 delete config.el; // hopefull!
45030 Roo.TreePanel.superclass.constructor.call(this, el, config);
45031 var treeEl = el.createChild();
45032 this.tree = new Roo.tree.TreePanel(treeEl , tree);
45033 //console.log(tree);
45034 this.on('activate', function()
45036 if (this.tree.rendered) {
45039 //console.log('render tree');
45040 this.tree.render();
45043 this.on('resize', function (cp, w, h) {
45044 this.tree.innerCt.setWidth(w);
45045 this.tree.innerCt.setHeight(h);
45046 this.tree.innerCt.setStyle('overflow-y', 'auto');
45053 Roo.extend(Roo.TreePanel, Roo.ContentPanel);
45067 * Ext JS Library 1.1.1
45068 * Copyright(c) 2006-2007, Ext JS, LLC.
45070 * Originally Released Under LGPL - original licence link has changed is not relivant.
45073 * <script type="text/javascript">
45078 * @class Roo.ReaderLayout
45079 * @extends Roo.BorderLayout
45080 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
45081 * center region containing two nested regions (a top one for a list view and one for item preview below),
45082 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
45083 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
45084 * expedites the setup of the overall layout and regions for this common application style.
45087 var reader = new Roo.ReaderLayout();
45088 var CP = Roo.ContentPanel; // shortcut for adding
45090 reader.beginUpdate();
45091 reader.add("north", new CP("north", "North"));
45092 reader.add("west", new CP("west", {title: "West"}));
45093 reader.add("east", new CP("east", {title: "East"}));
45095 reader.regions.listView.add(new CP("listView", "List"));
45096 reader.regions.preview.add(new CP("preview", "Preview"));
45097 reader.endUpdate();
45100 * Create a new ReaderLayout
45101 * @param {Object} config Configuration options
45102 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
45103 * document.body if omitted)
45105 Roo.ReaderLayout = function(config, renderTo){
45106 var c = config || {size:{}};
45107 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
45108 north: c.north !== false ? Roo.apply({
45112 }, c.north) : false,
45113 west: c.west !== false ? Roo.apply({
45121 margins:{left:5,right:0,bottom:5,top:5},
45122 cmargins:{left:5,right:5,bottom:5,top:5}
45123 }, c.west) : false,
45124 east: c.east !== false ? Roo.apply({
45132 margins:{left:0,right:5,bottom:5,top:5},
45133 cmargins:{left:5,right:5,bottom:5,top:5}
45134 }, c.east) : false,
45135 center: Roo.apply({
45136 tabPosition: 'top',
45140 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
45144 this.el.addClass('x-reader');
45146 this.beginUpdate();
45148 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
45149 south: c.preview !== false ? Roo.apply({
45156 cmargins:{top:5,left:0, right:0, bottom:0}
45157 }, c.preview) : false,
45158 center: Roo.apply({
45164 this.add('center', new Roo.NestedLayoutPanel(inner,
45165 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
45169 this.regions.preview = inner.getRegion('south');
45170 this.regions.listView = inner.getRegion('center');
45173 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
45175 * Ext JS Library 1.1.1
45176 * Copyright(c) 2006-2007, Ext JS, LLC.
45178 * Originally Released Under LGPL - original licence link has changed is not relivant.
45181 * <script type="text/javascript">
45185 * @class Roo.grid.Grid
45186 * @extends Roo.util.Observable
45187 * This class represents the primary interface of a component based grid control.
45188 * <br><br>Usage:<pre><code>
45189 var grid = new Roo.grid.Grid("my-container-id", {
45192 selModel: mySelectionModel,
45193 autoSizeColumns: true,
45194 monitorWindowResize: false,
45195 trackMouseOver: true
45200 * <b>Common Problems:</b><br/>
45201 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
45202 * element will correct this<br/>
45203 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
45204 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
45205 * are unpredictable.<br/>
45206 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
45207 * grid to calculate dimensions/offsets.<br/>
45209 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
45210 * The container MUST have some type of size defined for the grid to fill. The container will be
45211 * automatically set to position relative if it isn't already.
45212 * @param {Object} config A config object that sets properties on this grid.
45214 Roo.grid.Grid = function(container, config){
45215 // initialize the container
45216 this.container = Roo.get(container);
45217 this.container.update("");
45218 this.container.setStyle("overflow", "hidden");
45219 this.container.addClass('x-grid-container');
45221 this.id = this.container.id;
45223 Roo.apply(this, config);
45224 // check and correct shorthanded configs
45226 this.dataSource = this.ds;
45230 this.colModel = this.cm;
45234 this.selModel = this.sm;
45238 if (this.selModel) {
45239 this.selModel = Roo.factory(this.selModel, Roo.grid);
45240 this.sm = this.selModel;
45241 this.sm.xmodule = this.xmodule || false;
45243 if (typeof(this.colModel.config) == 'undefined') {
45244 this.colModel = new Roo.grid.ColumnModel(this.colModel);
45245 this.cm = this.colModel;
45246 this.cm.xmodule = this.xmodule || false;
45248 if (this.dataSource) {
45249 this.dataSource= Roo.factory(this.dataSource, Roo.data);
45250 this.ds = this.dataSource;
45251 this.ds.xmodule = this.xmodule || false;
45258 this.container.setWidth(this.width);
45262 this.container.setHeight(this.height);
45269 * The raw click event for the entire grid.
45270 * @param {Roo.EventObject} e
45275 * The raw dblclick event for the entire grid.
45276 * @param {Roo.EventObject} e
45280 * @event contextmenu
45281 * The raw contextmenu event for the entire grid.
45282 * @param {Roo.EventObject} e
45284 "contextmenu" : true,
45287 * The raw mousedown event for the entire grid.
45288 * @param {Roo.EventObject} e
45290 "mousedown" : true,
45293 * The raw mouseup event for the entire grid.
45294 * @param {Roo.EventObject} e
45299 * The raw mouseover event for the entire grid.
45300 * @param {Roo.EventObject} e
45302 "mouseover" : true,
45305 * The raw mouseout event for the entire grid.
45306 * @param {Roo.EventObject} e
45311 * The raw keypress event for the entire grid.
45312 * @param {Roo.EventObject} e
45317 * The raw keydown event for the entire grid.
45318 * @param {Roo.EventObject} e
45326 * Fires when a cell is clicked
45327 * @param {Grid} this
45328 * @param {Number} rowIndex
45329 * @param {Number} columnIndex
45330 * @param {Roo.EventObject} e
45332 "cellclick" : true,
45334 * @event celldblclick
45335 * Fires when a cell is double clicked
45336 * @param {Grid} this
45337 * @param {Number} rowIndex
45338 * @param {Number} columnIndex
45339 * @param {Roo.EventObject} e
45341 "celldblclick" : true,
45344 * Fires when a row is clicked
45345 * @param {Grid} this
45346 * @param {Number} rowIndex
45347 * @param {Roo.EventObject} e
45351 * @event rowdblclick
45352 * Fires when a row is double clicked
45353 * @param {Grid} this
45354 * @param {Number} rowIndex
45355 * @param {Roo.EventObject} e
45357 "rowdblclick" : true,
45359 * @event headerclick
45360 * Fires when a header is clicked
45361 * @param {Grid} this
45362 * @param {Number} columnIndex
45363 * @param {Roo.EventObject} e
45365 "headerclick" : true,
45367 * @event headerdblclick
45368 * Fires when a header cell is double clicked
45369 * @param {Grid} this
45370 * @param {Number} columnIndex
45371 * @param {Roo.EventObject} e
45373 "headerdblclick" : true,
45375 * @event rowcontextmenu
45376 * Fires when a row is right clicked
45377 * @param {Grid} this
45378 * @param {Number} rowIndex
45379 * @param {Roo.EventObject} e
45381 "rowcontextmenu" : true,
45383 * @event cellcontextmenu
45384 * Fires when a cell is right clicked
45385 * @param {Grid} this
45386 * @param {Number} rowIndex
45387 * @param {Number} cellIndex
45388 * @param {Roo.EventObject} e
45390 "cellcontextmenu" : true,
45392 * @event headercontextmenu
45393 * Fires when a header is right clicked
45394 * @param {Grid} this
45395 * @param {Number} columnIndex
45396 * @param {Roo.EventObject} e
45398 "headercontextmenu" : true,
45400 * @event bodyscroll
45401 * Fires when the body element is scrolled
45402 * @param {Number} scrollLeft
45403 * @param {Number} scrollTop
45405 "bodyscroll" : true,
45407 * @event columnresize
45408 * Fires when the user resizes a column
45409 * @param {Number} columnIndex
45410 * @param {Number} newSize
45412 "columnresize" : true,
45414 * @event columnmove
45415 * Fires when the user moves a column
45416 * @param {Number} oldIndex
45417 * @param {Number} newIndex
45419 "columnmove" : true,
45422 * Fires when row(s) start being dragged
45423 * @param {Grid} this
45424 * @param {Roo.GridDD} dd The drag drop object
45425 * @param {event} e The raw browser event
45427 "startdrag" : true,
45430 * Fires when a drag operation is complete
45431 * @param {Grid} this
45432 * @param {Roo.GridDD} dd The drag drop object
45433 * @param {event} e The raw browser event
45438 * Fires when dragged row(s) are dropped on a valid DD target
45439 * @param {Grid} this
45440 * @param {Roo.GridDD} dd The drag drop object
45441 * @param {String} targetId The target drag drop object
45442 * @param {event} e The raw browser event
45447 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
45448 * @param {Grid} this
45449 * @param {Roo.GridDD} dd The drag drop object
45450 * @param {String} targetId The target drag drop object
45451 * @param {event} e The raw browser event
45456 * Fires when the dragged row(s) first cross another DD target while being dragged
45457 * @param {Grid} this
45458 * @param {Roo.GridDD} dd The drag drop object
45459 * @param {String} targetId The target drag drop object
45460 * @param {event} e The raw browser event
45462 "dragenter" : true,
45465 * Fires when the dragged row(s) leave another DD target while being dragged
45466 * @param {Grid} this
45467 * @param {Roo.GridDD} dd The drag drop object
45468 * @param {String} targetId The target drag drop object
45469 * @param {event} e The raw browser event
45474 * Fires when the grid is rendered
45475 * @param {Grid} grid
45480 Roo.grid.Grid.superclass.constructor.call(this);
45482 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
45484 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
45486 minColumnWidth : 25,
45489 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
45490 * <b>on initial render.</b> It is more efficient to explicitly size the columns
45491 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
45493 autoSizeColumns : false,
45496 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
45498 autoSizeHeaders : true,
45501 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
45503 monitorWindowResize : true,
45506 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
45507 * rows measured to get a columns size. Default is 0 (all rows).
45509 maxRowsToMeasure : 0,
45512 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
45514 trackMouseOver : true,
45517 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
45519 enableDragDrop : false,
45522 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
45524 enableColumnMove : true,
45527 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
45529 enableColumnHide : true,
45532 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
45534 enableRowHeightSync : false,
45537 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
45542 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
45544 autoHeight : false,
45547 * @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.
45549 autoExpandColumn : false,
45552 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
45555 autoExpandMin : 50,
45558 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
45560 autoExpandMax : 1000,
45563 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
45568 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
45576 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
45577 * of a fixed width. Default is false.
45580 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
45583 * Called once after all setup has been completed and the grid is ready to be rendered.
45584 * @return {Roo.grid.Grid} this
45586 render : function(){
45587 var c = this.container;
45588 // try to detect autoHeight/width mode
45589 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
45590 this.autoHeight = true;
45592 var view = this.getView();
45595 c.on("click", this.onClick, this);
45596 c.on("dblclick", this.onDblClick, this);
45597 c.on("contextmenu", this.onContextMenu, this);
45598 c.on("keydown", this.onKeyDown, this);
45600 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
45602 this.getSelectionModel().init(this);
45607 this.loadMask = new Roo.LoadMask(this.container,
45608 Roo.apply({store:this.dataSource}, this.loadMask));
45612 if (this.toolbar && this.toolbar.xtype) {
45613 this.toolbar.container = this.getView().getHeaderPanel(true);
45614 this.toolbar = new Ext.Toolbar(this.toolbar);
45616 if (this.footer && this.footer.xtype) {
45617 this.footer.dataSource = this.getDataSource();
45618 this.footer.container = this.getView().getFooterPanel(true);
45619 this.footer = Roo.factory(this.footer, Roo);
45621 this.rendered = true;
45622 this.fireEvent('render', this);
45627 * Reconfigures the grid to use a different Store and Column Model.
45628 * The View will be bound to the new objects and refreshed.
45629 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
45630 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
45632 reconfigure : function(dataSource, colModel){
45634 this.loadMask.destroy();
45635 this.loadMask = new Roo.LoadMask(this.container,
45636 Roo.apply({store:dataSource}, this.loadMask));
45638 this.view.bind(dataSource, colModel);
45639 this.dataSource = dataSource;
45640 this.colModel = colModel;
45641 this.view.refresh(true);
45645 onKeyDown : function(e){
45646 this.fireEvent("keydown", e);
45650 * Destroy this grid.
45651 * @param {Boolean} removeEl True to remove the element
45653 destroy : function(removeEl, keepListeners){
45655 this.loadMask.destroy();
45657 var c = this.container;
45658 c.removeAllListeners();
45659 this.view.destroy();
45660 this.colModel.purgeListeners();
45661 if(!keepListeners){
45662 this.purgeListeners();
45665 if(removeEl === true){
45671 processEvent : function(name, e){
45672 this.fireEvent(name, e);
45673 var t = e.getTarget();
45675 var header = v.findHeaderIndex(t);
45676 if(header !== false){
45677 this.fireEvent("header" + name, this, header, e);
45679 var row = v.findRowIndex(t);
45680 var cell = v.findCellIndex(t);
45682 this.fireEvent("row" + name, this, row, e);
45683 if(cell !== false){
45684 this.fireEvent("cell" + name, this, row, cell, e);
45691 onClick : function(e){
45692 this.processEvent("click", e);
45696 onContextMenu : function(e, t){
45697 this.processEvent("contextmenu", e);
45701 onDblClick : function(e){
45702 this.processEvent("dblclick", e);
45706 walkCells : function(row, col, step, fn, scope){
45707 var cm = this.colModel, clen = cm.getColumnCount();
45708 var ds = this.dataSource, rlen = ds.getCount(), first = true;
45720 if(fn.call(scope || this, row, col, cm) === true){
45738 if(fn.call(scope || this, row, col, cm) === true){
45750 getSelections : function(){
45751 return this.selModel.getSelections();
45755 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
45756 * but if manual update is required this method will initiate it.
45758 autoSize : function(){
45760 this.view.layout();
45761 if(this.view.adjustForScroll){
45762 this.view.adjustForScroll();
45768 * Returns the grid's underlying element.
45769 * @return {Element} The element
45771 getGridEl : function(){
45772 return this.container;
45775 // private for compatibility, overridden by editor grid
45776 stopEditing : function(){},
45779 * Returns the grid's SelectionModel.
45780 * @return {SelectionModel}
45782 getSelectionModel : function(){
45783 if(!this.selModel){
45784 this.selModel = new Roo.grid.RowSelectionModel();
45786 return this.selModel;
45790 * Returns the grid's DataSource.
45791 * @return {DataSource}
45793 getDataSource : function(){
45794 return this.dataSource;
45798 * Returns the grid's ColumnModel.
45799 * @return {ColumnModel}
45801 getColumnModel : function(){
45802 return this.colModel;
45806 * Returns the grid's GridView object.
45807 * @return {GridView}
45809 getView : function(){
45811 this.view = new Roo.grid.GridView(this.viewConfig);
45816 * Called to get grid's drag proxy text, by default returns this.ddText.
45819 getDragDropText : function(){
45820 var count = this.selModel.getCount();
45821 return String.format(this.ddText, count, count == 1 ? '' : 's');
45825 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
45826 * %0 is replaced with the number of selected rows.
45829 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
45831 * Ext JS Library 1.1.1
45832 * Copyright(c) 2006-2007, Ext JS, LLC.
45834 * Originally Released Under LGPL - original licence link has changed is not relivant.
45837 * <script type="text/javascript">
45840 Roo.grid.AbstractGridView = function(){
45844 "beforerowremoved" : true,
45845 "beforerowsinserted" : true,
45846 "beforerefresh" : true,
45847 "rowremoved" : true,
45848 "rowsinserted" : true,
45849 "rowupdated" : true,
45852 Roo.grid.AbstractGridView.superclass.constructor.call(this);
45855 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
45856 rowClass : "x-grid-row",
45857 cellClass : "x-grid-cell",
45858 tdClass : "x-grid-td",
45859 hdClass : "x-grid-hd",
45860 splitClass : "x-grid-hd-split",
45862 init: function(grid){
45864 var cid = this.grid.getGridEl().id;
45865 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
45866 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
45867 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
45868 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
45871 getColumnRenderers : function(){
45872 var renderers = [];
45873 var cm = this.grid.colModel;
45874 var colCount = cm.getColumnCount();
45875 for(var i = 0; i < colCount; i++){
45876 renderers[i] = cm.getRenderer(i);
45881 getColumnIds : function(){
45883 var cm = this.grid.colModel;
45884 var colCount = cm.getColumnCount();
45885 for(var i = 0; i < colCount; i++){
45886 ids[i] = cm.getColumnId(i);
45891 getDataIndexes : function(){
45892 if(!this.indexMap){
45893 this.indexMap = this.buildIndexMap();
45895 return this.indexMap.colToData;
45898 getColumnIndexByDataIndex : function(dataIndex){
45899 if(!this.indexMap){
45900 this.indexMap = this.buildIndexMap();
45902 return this.indexMap.dataToCol[dataIndex];
45906 * Set a css style for a column dynamically.
45907 * @param {Number} colIndex The index of the column
45908 * @param {String} name The css property name
45909 * @param {String} value The css value
45911 setCSSStyle : function(colIndex, name, value){
45912 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
45913 Roo.util.CSS.updateRule(selector, name, value);
45916 generateRules : function(cm){
45917 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
45918 Roo.util.CSS.removeStyleSheet(rulesId);
45919 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
45920 var cid = cm.getColumnId(i);
45921 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
45922 this.tdSelector, cid, " {\n}\n",
45923 this.hdSelector, cid, " {\n}\n",
45924 this.splitSelector, cid, " {\n}\n");
45926 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
45930 * Ext JS Library 1.1.1
45931 * Copyright(c) 2006-2007, Ext JS, LLC.
45933 * Originally Released Under LGPL - original licence link has changed is not relivant.
45936 * <script type="text/javascript">
45940 // This is a support class used internally by the Grid components
45941 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
45943 this.view = grid.getView();
45944 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45945 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
45947 this.setHandleElId(Roo.id(hd));
45948 this.setOuterHandleElId(Roo.id(hd2));
45950 this.scroll = false;
45952 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
45954 getDragData : function(e){
45955 var t = Roo.lib.Event.getTarget(e);
45956 var h = this.view.findHeaderCell(t);
45958 return {ddel: h.firstChild, header:h};
45963 onInitDrag : function(e){
45964 this.view.headersDisabled = true;
45965 var clone = this.dragData.ddel.cloneNode(true);
45966 clone.id = Roo.id();
45967 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
45968 this.proxy.update(clone);
45972 afterValidDrop : function(){
45974 setTimeout(function(){
45975 v.headersDisabled = false;
45979 afterInvalidDrop : function(){
45981 setTimeout(function(){
45982 v.headersDisabled = false;
45988 * Ext JS Library 1.1.1
45989 * Copyright(c) 2006-2007, Ext JS, LLC.
45991 * Originally Released Under LGPL - original licence link has changed is not relivant.
45994 * <script type="text/javascript">
45997 // This is a support class used internally by the Grid components
45998 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
46000 this.view = grid.getView();
46001 // split the proxies so they don't interfere with mouse events
46002 this.proxyTop = Roo.DomHelper.append(document.body, {
46003 cls:"col-move-top", html:" "
46005 this.proxyBottom = Roo.DomHelper.append(document.body, {
46006 cls:"col-move-bottom", html:" "
46008 this.proxyTop.hide = this.proxyBottom.hide = function(){
46009 this.setLeftTop(-100,-100);
46010 this.setStyle("visibility", "hidden");
46012 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46013 // temporarily disabled
46014 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
46015 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
46017 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
46018 proxyOffsets : [-4, -9],
46019 fly: Roo.Element.fly,
46021 getTargetFromEvent : function(e){
46022 var t = Roo.lib.Event.getTarget(e);
46023 var cindex = this.view.findCellIndex(t);
46024 if(cindex !== false){
46025 return this.view.getHeaderCell(cindex);
46029 nextVisible : function(h){
46030 var v = this.view, cm = this.grid.colModel;
46033 if(!cm.isHidden(v.getCellIndex(h))){
46041 prevVisible : function(h){
46042 var v = this.view, cm = this.grid.colModel;
46045 if(!cm.isHidden(v.getCellIndex(h))){
46053 positionIndicator : function(h, n, e){
46054 var x = Roo.lib.Event.getPageX(e);
46055 var r = Roo.lib.Dom.getRegion(n.firstChild);
46056 var px, pt, py = r.top + this.proxyOffsets[1];
46057 if((r.right - x) <= (r.right-r.left)/2){
46058 px = r.right+this.view.borderWidth;
46064 var oldIndex = this.view.getCellIndex(h);
46065 var newIndex = this.view.getCellIndex(n);
46067 if(this.grid.colModel.isFixed(newIndex)){
46071 var locked = this.grid.colModel.isLocked(newIndex);
46076 if(oldIndex < newIndex){
46079 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
46082 px += this.proxyOffsets[0];
46083 this.proxyTop.setLeftTop(px, py);
46084 this.proxyTop.show();
46085 if(!this.bottomOffset){
46086 this.bottomOffset = this.view.mainHd.getHeight();
46088 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
46089 this.proxyBottom.show();
46093 onNodeEnter : function(n, dd, e, data){
46094 if(data.header != n){
46095 this.positionIndicator(data.header, n, e);
46099 onNodeOver : function(n, dd, e, data){
46100 var result = false;
46101 if(data.header != n){
46102 result = this.positionIndicator(data.header, n, e);
46105 this.proxyTop.hide();
46106 this.proxyBottom.hide();
46108 return result ? this.dropAllowed : this.dropNotAllowed;
46111 onNodeOut : function(n, dd, e, data){
46112 this.proxyTop.hide();
46113 this.proxyBottom.hide();
46116 onNodeDrop : function(n, dd, e, data){
46117 var h = data.header;
46119 var cm = this.grid.colModel;
46120 var x = Roo.lib.Event.getPageX(e);
46121 var r = Roo.lib.Dom.getRegion(n.firstChild);
46122 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
46123 var oldIndex = this.view.getCellIndex(h);
46124 var newIndex = this.view.getCellIndex(n);
46125 var locked = cm.isLocked(newIndex);
46129 if(oldIndex < newIndex){
46132 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
46135 cm.setLocked(oldIndex, locked, true);
46136 cm.moveColumn(oldIndex, newIndex);
46137 this.grid.fireEvent("columnmove", oldIndex, newIndex);
46145 * Ext JS Library 1.1.1
46146 * Copyright(c) 2006-2007, Ext JS, LLC.
46148 * Originally Released Under LGPL - original licence link has changed is not relivant.
46151 * <script type="text/javascript">
46155 * @class Roo.grid.GridView
46156 * @extends Roo.util.Observable
46159 * @param {Object} config
46161 Roo.grid.GridView = function(config){
46162 Roo.grid.GridView.superclass.constructor.call(this);
46165 Roo.apply(this, config);
46168 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
46171 * Override this function to apply custom css classes to rows during rendering
46172 * @param {Record} record The record
46173 * @param {Number} index
46174 * @method getRowClass
46176 rowClass : "x-grid-row",
46178 cellClass : "x-grid-col",
46180 tdClass : "x-grid-td",
46182 hdClass : "x-grid-hd",
46184 splitClass : "x-grid-split",
46186 sortClasses : ["sort-asc", "sort-desc"],
46188 enableMoveAnim : false,
46192 dh : Roo.DomHelper,
46194 fly : Roo.Element.fly,
46196 css : Roo.util.CSS,
46202 scrollIncrement : 22,
46204 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
46206 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
46208 bind : function(ds, cm){
46210 this.ds.un("load", this.onLoad, this);
46211 this.ds.un("datachanged", this.onDataChange, this);
46212 this.ds.un("add", this.onAdd, this);
46213 this.ds.un("remove", this.onRemove, this);
46214 this.ds.un("update", this.onUpdate, this);
46215 this.ds.un("clear", this.onClear, this);
46218 ds.on("load", this.onLoad, this);
46219 ds.on("datachanged", this.onDataChange, this);
46220 ds.on("add", this.onAdd, this);
46221 ds.on("remove", this.onRemove, this);
46222 ds.on("update", this.onUpdate, this);
46223 ds.on("clear", this.onClear, this);
46228 this.cm.un("widthchange", this.onColWidthChange, this);
46229 this.cm.un("headerchange", this.onHeaderChange, this);
46230 this.cm.un("hiddenchange", this.onHiddenChange, this);
46231 this.cm.un("columnmoved", this.onColumnMove, this);
46232 this.cm.un("columnlockchange", this.onColumnLock, this);
46235 this.generateRules(cm);
46236 cm.on("widthchange", this.onColWidthChange, this);
46237 cm.on("headerchange", this.onHeaderChange, this);
46238 cm.on("hiddenchange", this.onHiddenChange, this);
46239 cm.on("columnmoved", this.onColumnMove, this);
46240 cm.on("columnlockchange", this.onColumnLock, this);
46245 init: function(grid){
46246 Roo.grid.GridView.superclass.init.call(this, grid);
46248 this.bind(grid.dataSource, grid.colModel);
46250 grid.on("headerclick", this.handleHeaderClick, this);
46252 if(grid.trackMouseOver){
46253 grid.on("mouseover", this.onRowOver, this);
46254 grid.on("mouseout", this.onRowOut, this);
46256 grid.cancelTextSelection = function(){};
46257 this.gridId = grid.id;
46259 var tpls = this.templates || {};
46262 tpls.master = new Roo.Template(
46263 '<div class="x-grid" hidefocus="true">',
46264 '<div class="x-grid-topbar"></div>',
46265 '<div class="x-grid-scroller"><div></div></div>',
46266 '<div class="x-grid-locked">',
46267 '<div class="x-grid-header">{lockedHeader}</div>',
46268 '<div class="x-grid-body">{lockedBody}</div>',
46270 '<div class="x-grid-viewport">',
46271 '<div class="x-grid-header">{header}</div>',
46272 '<div class="x-grid-body">{body}</div>',
46274 '<div class="x-grid-bottombar"></div>',
46275 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
46276 '<div class="x-grid-resize-proxy"> </div>',
46279 tpls.master.disableformats = true;
46283 tpls.header = new Roo.Template(
46284 '<table border="0" cellspacing="0" cellpadding="0">',
46285 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
46288 tpls.header.disableformats = true;
46290 tpls.header.compile();
46293 tpls.hcell = new Roo.Template(
46294 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
46295 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
46298 tpls.hcell.disableFormats = true;
46300 tpls.hcell.compile();
46303 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
46304 tpls.hsplit.disableFormats = true;
46306 tpls.hsplit.compile();
46309 tpls.body = new Roo.Template(
46310 '<table border="0" cellspacing="0" cellpadding="0">',
46311 "<tbody>{rows}</tbody>",
46314 tpls.body.disableFormats = true;
46316 tpls.body.compile();
46319 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
46320 tpls.row.disableFormats = true;
46322 tpls.row.compile();
46325 tpls.cell = new Roo.Template(
46326 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
46327 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
46330 tpls.cell.disableFormats = true;
46332 tpls.cell.compile();
46334 this.templates = tpls;
46337 // remap these for backwards compat
46338 onColWidthChange : function(){
46339 this.updateColumns.apply(this, arguments);
46341 onHeaderChange : function(){
46342 this.updateHeaders.apply(this, arguments);
46344 onHiddenChange : function(){
46345 this.handleHiddenChange.apply(this, arguments);
46347 onColumnMove : function(){
46348 this.handleColumnMove.apply(this, arguments);
46350 onColumnLock : function(){
46351 this.handleLockChange.apply(this, arguments);
46354 onDataChange : function(){
46356 this.updateHeaderSortState();
46359 onClear : function(){
46363 onUpdate : function(ds, record){
46364 this.refreshRow(record);
46367 refreshRow : function(record){
46368 var ds = this.ds, index;
46369 if(typeof record == 'number'){
46371 record = ds.getAt(index);
46373 index = ds.indexOf(record);
46375 this.insertRows(ds, index, index, true);
46376 this.onRemove(ds, record, index+1, true);
46377 this.syncRowHeights(index, index);
46379 this.fireEvent("rowupdated", this, index, record);
46382 onAdd : function(ds, records, index){
46383 this.insertRows(ds, index, index + (records.length-1));
46386 onRemove : function(ds, record, index, isUpdate){
46387 if(isUpdate !== true){
46388 this.fireEvent("beforerowremoved", this, index, record);
46390 var bt = this.getBodyTable(), lt = this.getLockedTable();
46391 if(bt.rows[index]){
46392 bt.firstChild.removeChild(bt.rows[index]);
46394 if(lt.rows[index]){
46395 lt.firstChild.removeChild(lt.rows[index]);
46397 if(isUpdate !== true){
46398 this.stripeRows(index);
46399 this.syncRowHeights(index, index);
46401 this.fireEvent("rowremoved", this, index, record);
46405 onLoad : function(){
46406 this.scrollToTop();
46410 * Scrolls the grid to the top
46412 scrollToTop : function(){
46414 this.scroller.dom.scrollTop = 0;
46420 * Gets a panel in the header of the grid that can be used for toolbars etc.
46421 * After modifying the contents of this panel a call to grid.autoSize() may be
46422 * required to register any changes in size.
46423 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
46424 * @return Roo.Element
46426 getHeaderPanel : function(doShow){
46428 this.headerPanel.show();
46430 return this.headerPanel;
46434 * Gets a panel in the footer of the grid that can be used for toolbars etc.
46435 * After modifying the contents of this panel a call to grid.autoSize() may be
46436 * required to register any changes in size.
46437 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
46438 * @return Roo.Element
46440 getFooterPanel : function(doShow){
46442 this.footerPanel.show();
46444 return this.footerPanel;
46447 initElements : function(){
46448 var E = Roo.Element;
46449 var el = this.grid.getGridEl().dom.firstChild;
46450 var cs = el.childNodes;
46452 this.el = new E(el);
46453 this.headerPanel = new E(el.firstChild);
46454 this.headerPanel.enableDisplayMode("block");
46456 this.scroller = new E(cs[1]);
46457 this.scrollSizer = new E(this.scroller.dom.firstChild);
46459 this.lockedWrap = new E(cs[2]);
46460 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
46461 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
46463 this.mainWrap = new E(cs[3]);
46464 this.mainHd = new E(this.mainWrap.dom.firstChild);
46465 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
46467 this.footerPanel = new E(cs[4]);
46468 this.footerPanel.enableDisplayMode("block");
46470 this.focusEl = new E(cs[5]);
46471 this.focusEl.swallowEvent("click", true);
46472 this.resizeProxy = new E(cs[6]);
46474 this.headerSelector = String.format(
46475 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
46476 this.lockedHd.id, this.mainHd.id
46479 this.splitterSelector = String.format(
46480 '#{0} div.x-grid-split, #{1} div.x-grid-split',
46481 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
46484 idToCssName : function(s)
46486 return s.replace(/[^a-z0-9]+/ig, '-');
46489 getHeaderCell : function(index){
46490 return Roo.DomQuery.select(this.headerSelector)[index];
46493 getHeaderCellMeasure : function(index){
46494 return this.getHeaderCell(index).firstChild;
46497 getHeaderCellText : function(index){
46498 return this.getHeaderCell(index).firstChild.firstChild;
46501 getLockedTable : function(){
46502 return this.lockedBody.dom.firstChild;
46505 getBodyTable : function(){
46506 return this.mainBody.dom.firstChild;
46509 getLockedRow : function(index){
46510 return this.getLockedTable().rows[index];
46513 getRow : function(index){
46514 return this.getBodyTable().rows[index];
46517 getRowComposite : function(index){
46519 this.rowEl = new Roo.CompositeElementLite();
46521 var els = [], lrow, mrow;
46522 if(lrow = this.getLockedRow(index)){
46525 if(mrow = this.getRow(index)){
46528 this.rowEl.elements = els;
46532 getCell : function(rowIndex, colIndex){
46533 var locked = this.cm.getLockedCount();
46535 if(colIndex < locked){
46536 source = this.lockedBody.dom.firstChild;
46538 source = this.mainBody.dom.firstChild;
46539 colIndex -= locked;
46541 return source.rows[rowIndex].childNodes[colIndex];
46544 getCellText : function(rowIndex, colIndex){
46545 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
46548 getCellBox : function(cell){
46549 var b = this.fly(cell).getBox();
46550 if(Roo.isOpera){ // opera fails to report the Y
46551 b.y = cell.offsetTop + this.mainBody.getY();
46556 getCellIndex : function(cell){
46557 var id = String(cell.className).match(this.cellRE);
46559 return parseInt(id[1], 10);
46564 findHeaderIndex : function(n){
46565 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46566 return r ? this.getCellIndex(r) : false;
46569 findHeaderCell : function(n){
46570 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46571 return r ? r : false;
46574 findRowIndex : function(n){
46578 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
46579 return r ? r.rowIndex : false;
46582 findCellIndex : function(node){
46583 var stop = this.el.dom;
46584 while(node && node != stop){
46585 if(this.findRE.test(node.className)){
46586 return this.getCellIndex(node);
46588 node = node.parentNode;
46593 getColumnId : function(index){
46594 return this.cm.getColumnId(index);
46597 getSplitters : function(){
46598 if(this.splitterSelector){
46599 return Roo.DomQuery.select(this.splitterSelector);
46605 getSplitter : function(index){
46606 return this.getSplitters()[index];
46609 onRowOver : function(e, t){
46611 if((row = this.findRowIndex(t)) !== false){
46612 this.getRowComposite(row).addClass("x-grid-row-over");
46616 onRowOut : function(e, t){
46618 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
46619 this.getRowComposite(row).removeClass("x-grid-row-over");
46623 renderHeaders : function(){
46625 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
46626 var cb = [], lb = [], sb = [], lsb = [], p = {};
46627 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46628 p.cellId = "x-grid-hd-0-" + i;
46629 p.splitId = "x-grid-csplit-0-" + i;
46630 p.id = cm.getColumnId(i);
46631 p.title = cm.getColumnTooltip(i) || "";
46632 p.value = cm.getColumnHeader(i) || "";
46633 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
46634 if(!cm.isLocked(i)){
46635 cb[cb.length] = ct.apply(p);
46636 sb[sb.length] = st.apply(p);
46638 lb[lb.length] = ct.apply(p);
46639 lsb[lsb.length] = st.apply(p);
46642 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
46643 ht.apply({cells: cb.join(""), splits:sb.join("")})];
46646 updateHeaders : function(){
46647 var html = this.renderHeaders();
46648 this.lockedHd.update(html[0]);
46649 this.mainHd.update(html[1]);
46653 * Focuses the specified row.
46654 * @param {Number} row The row index
46656 focusRow : function(row){
46657 var x = this.scroller.dom.scrollLeft;
46658 this.focusCell(row, 0, false);
46659 this.scroller.dom.scrollLeft = x;
46663 * Focuses the specified cell.
46664 * @param {Number} row The row index
46665 * @param {Number} col The column index
46666 * @param {Boolean} hscroll false to disable horizontal scrolling
46668 focusCell : function(row, col, hscroll){
46669 var el = this.ensureVisible(row, col, hscroll);
46670 this.focusEl.alignTo(el, "tl-tl");
46672 this.focusEl.focus();
46674 this.focusEl.focus.defer(1, this.focusEl);
46679 * Scrolls the specified cell into view
46680 * @param {Number} row The row index
46681 * @param {Number} col The column index
46682 * @param {Boolean} hscroll false to disable horizontal scrolling
46684 ensureVisible : function(row, col, hscroll){
46685 if(typeof row != "number"){
46686 row = row.rowIndex;
46688 if(row < 0 && row >= this.ds.getCount()){
46691 col = (col !== undefined ? col : 0);
46692 var cm = this.grid.colModel;
46693 while(cm.isHidden(col)){
46697 var el = this.getCell(row, col);
46701 var c = this.scroller.dom;
46703 var ctop = parseInt(el.offsetTop, 10);
46704 var cleft = parseInt(el.offsetLeft, 10);
46705 var cbot = ctop + el.offsetHeight;
46706 var cright = cleft + el.offsetWidth;
46708 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
46709 var stop = parseInt(c.scrollTop, 10);
46710 var sleft = parseInt(c.scrollLeft, 10);
46711 var sbot = stop + ch;
46712 var sright = sleft + c.clientWidth;
46715 c.scrollTop = ctop;
46716 }else if(cbot > sbot){
46717 c.scrollTop = cbot-ch;
46720 if(hscroll !== false){
46722 c.scrollLeft = cleft;
46723 }else if(cright > sright){
46724 c.scrollLeft = cright-c.clientWidth;
46730 updateColumns : function(){
46731 this.grid.stopEditing();
46732 var cm = this.grid.colModel, colIds = this.getColumnIds();
46733 //var totalWidth = cm.getTotalWidth();
46735 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46736 //if(cm.isHidden(i)) continue;
46737 var w = cm.getColumnWidth(i);
46738 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46739 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46741 this.updateSplitters();
46744 generateRules : function(cm){
46745 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
46746 Roo.util.CSS.removeStyleSheet(rulesId);
46747 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46748 var cid = cm.getColumnId(i);
46750 if(cm.config[i].align){
46751 align = 'text-align:'+cm.config[i].align+';';
46754 if(cm.isHidden(i)){
46755 hidden = 'display:none;';
46757 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
46759 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
46760 this.hdSelector, cid, " {\n", align, width, "}\n",
46761 this.tdSelector, cid, " {\n",hidden,"\n}\n",
46762 this.splitSelector, cid, " {\n", hidden , "\n}\n");
46764 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46767 updateSplitters : function(){
46768 var cm = this.cm, s = this.getSplitters();
46769 if(s){ // splitters not created yet
46770 var pos = 0, locked = true;
46771 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46772 if(cm.isHidden(i)) continue;
46773 var w = cm.getColumnWidth(i);
46774 if(!cm.isLocked(i) && locked){
46779 s[i].style.left = (pos-this.splitOffset) + "px";
46784 handleHiddenChange : function(colModel, colIndex, hidden){
46786 this.hideColumn(colIndex);
46788 this.unhideColumn(colIndex);
46792 hideColumn : function(colIndex){
46793 var cid = this.getColumnId(colIndex);
46794 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
46795 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
46797 this.updateHeaders();
46799 this.updateSplitters();
46803 unhideColumn : function(colIndex){
46804 var cid = this.getColumnId(colIndex);
46805 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
46806 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
46809 this.updateHeaders();
46811 this.updateSplitters();
46815 insertRows : function(dm, firstRow, lastRow, isUpdate){
46816 if(firstRow == 0 && lastRow == dm.getCount()-1){
46820 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
46822 var s = this.getScrollState();
46823 var markup = this.renderRows(firstRow, lastRow);
46824 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
46825 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
46826 this.restoreScroll(s);
46828 this.fireEvent("rowsinserted", this, firstRow, lastRow);
46829 this.syncRowHeights(firstRow, lastRow);
46830 this.stripeRows(firstRow);
46836 bufferRows : function(markup, target, index){
46837 var before = null, trows = target.rows, tbody = target.tBodies[0];
46838 if(index < trows.length){
46839 before = trows[index];
46841 var b = document.createElement("div");
46842 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
46843 var rows = b.firstChild.rows;
46844 for(var i = 0, len = rows.length; i < len; i++){
46846 tbody.insertBefore(rows[0], before);
46848 tbody.appendChild(rows[0]);
46855 deleteRows : function(dm, firstRow, lastRow){
46856 if(dm.getRowCount()<1){
46857 this.fireEvent("beforerefresh", this);
46858 this.mainBody.update("");
46859 this.lockedBody.update("");
46860 this.fireEvent("refresh", this);
46862 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
46863 var bt = this.getBodyTable();
46864 var tbody = bt.firstChild;
46865 var rows = bt.rows;
46866 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
46867 tbody.removeChild(rows[firstRow]);
46869 this.stripeRows(firstRow);
46870 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
46874 updateRows : function(dataSource, firstRow, lastRow){
46875 var s = this.getScrollState();
46877 this.restoreScroll(s);
46880 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
46884 this.updateHeaderSortState();
46887 getScrollState : function(){
46888 var sb = this.scroller.dom;
46889 return {left: sb.scrollLeft, top: sb.scrollTop};
46892 stripeRows : function(startRow){
46893 if(!this.grid.stripeRows || this.ds.getCount() < 1){
46896 startRow = startRow || 0;
46897 var rows = this.getBodyTable().rows;
46898 var lrows = this.getLockedTable().rows;
46899 var cls = ' x-grid-row-alt ';
46900 for(var i = startRow, len = rows.length; i < len; i++){
46901 var row = rows[i], lrow = lrows[i];
46902 var isAlt = ((i+1) % 2 == 0);
46903 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
46904 if(isAlt == hasAlt){
46908 row.className += " x-grid-row-alt";
46910 row.className = row.className.replace("x-grid-row-alt", "");
46913 lrow.className = row.className;
46918 restoreScroll : function(state){
46919 var sb = this.scroller.dom;
46920 sb.scrollLeft = state.left;
46921 sb.scrollTop = state.top;
46925 syncScroll : function(){
46926 var sb = this.scroller.dom;
46927 var sh = this.mainHd.dom;
46928 var bs = this.mainBody.dom;
46929 var lv = this.lockedBody.dom;
46930 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
46931 lv.scrollTop = bs.scrollTop = sb.scrollTop;
46934 handleScroll : function(e){
46936 var sb = this.scroller.dom;
46937 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
46941 handleWheel : function(e){
46942 var d = e.getWheelDelta();
46943 this.scroller.dom.scrollTop -= d*22;
46944 // set this here to prevent jumpy scrolling on large tables
46945 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
46949 renderRows : function(startRow, endRow){
46950 // pull in all the crap needed to render rows
46951 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
46952 var colCount = cm.getColumnCount();
46954 if(ds.getCount() < 1){
46958 // build a map for all the columns
46960 for(var i = 0; i < colCount; i++){
46961 var name = cm.getDataIndex(i);
46963 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
46964 renderer : cm.getRenderer(i),
46965 id : cm.getColumnId(i),
46966 locked : cm.isLocked(i)
46970 startRow = startRow || 0;
46971 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
46973 // records to render
46974 var rs = ds.getRange(startRow, endRow);
46976 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
46979 // As much as I hate to duplicate code, this was branched because FireFox really hates
46980 // [].join("") on strings. The performance difference was substantial enough to
46981 // branch this function
46982 doRender : Roo.isGecko ?
46983 function(cs, rs, ds, startRow, colCount, stripe){
46984 var ts = this.templates, ct = ts.cell, rt = ts.row;
46986 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46987 for(var j = 0, len = rs.length; j < len; j++){
46988 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
46989 for(var i = 0; i < colCount; i++){
46991 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46993 p.css = p.attr = "";
46994 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46995 if(p.value == undefined || p.value === "") p.value = " ";
46996 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46997 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
46999 var markup = ct.apply(p);
47007 if(stripe && ((rowIndex+1) % 2 == 0)){
47008 alt[0] = "x-grid-row-alt";
47011 alt[1] = " x-grid-dirty-row";
47014 if(this.getRowClass){
47015 alt[2] = this.getRowClass(r, rowIndex);
47017 rp.alt = alt.join(" ");
47018 lbuf+= rt.apply(rp);
47020 buf+= rt.apply(rp);
47022 return [lbuf, buf];
47024 function(cs, rs, ds, startRow, colCount, stripe){
47025 var ts = this.templates, ct = ts.cell, rt = ts.row;
47027 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47028 for(var j = 0, len = rs.length; j < len; j++){
47029 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
47030 for(var i = 0; i < colCount; i++){
47032 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47034 p.css = p.attr = "";
47035 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47036 if(p.value == undefined || p.value === "") p.value = " ";
47037 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47038 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47040 var markup = ct.apply(p);
47042 cb[cb.length] = markup;
47044 lcb[lcb.length] = markup;
47048 if(stripe && ((rowIndex+1) % 2 == 0)){
47049 alt[0] = "x-grid-row-alt";
47052 alt[1] = " x-grid-dirty-row";
47055 if(this.getRowClass){
47056 alt[2] = this.getRowClass(r, rowIndex);
47058 rp.alt = alt.join(" ");
47059 rp.cells = lcb.join("");
47060 lbuf[lbuf.length] = rt.apply(rp);
47061 rp.cells = cb.join("");
47062 buf[buf.length] = rt.apply(rp);
47064 return [lbuf.join(""), buf.join("")];
47067 renderBody : function(){
47068 var markup = this.renderRows();
47069 var bt = this.templates.body;
47070 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
47074 * Refreshes the grid
47075 * @param {Boolean} headersToo
47077 refresh : function(headersToo){
47078 this.fireEvent("beforerefresh", this);
47079 this.grid.stopEditing();
47080 var result = this.renderBody();
47081 this.lockedBody.update(result[0]);
47082 this.mainBody.update(result[1]);
47083 if(headersToo === true){
47084 this.updateHeaders();
47085 this.updateColumns();
47086 this.updateSplitters();
47087 this.updateHeaderSortState();
47089 this.syncRowHeights();
47091 this.fireEvent("refresh", this);
47094 handleColumnMove : function(cm, oldIndex, newIndex){
47095 this.indexMap = null;
47096 var s = this.getScrollState();
47097 this.refresh(true);
47098 this.restoreScroll(s);
47099 this.afterMove(newIndex);
47102 afterMove : function(colIndex){
47103 if(this.enableMoveAnim && Roo.enableFx){
47104 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
47108 updateCell : function(dm, rowIndex, dataIndex){
47109 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
47110 if(typeof colIndex == "undefined"){ // not present in grid
47113 var cm = this.grid.colModel;
47114 var cell = this.getCell(rowIndex, colIndex);
47115 var cellText = this.getCellText(rowIndex, colIndex);
47118 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
47119 id : cm.getColumnId(colIndex),
47120 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
47122 var renderer = cm.getRenderer(colIndex);
47123 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
47124 if(typeof val == "undefined" || val === "") val = " ";
47125 cellText.innerHTML = val;
47126 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
47127 this.syncRowHeights(rowIndex, rowIndex);
47130 calcColumnWidth : function(colIndex, maxRowsToMeasure){
47132 if(this.grid.autoSizeHeaders){
47133 var h = this.getHeaderCellMeasure(colIndex);
47134 maxWidth = Math.max(maxWidth, h.scrollWidth);
47137 if(this.cm.isLocked(colIndex)){
47138 tb = this.getLockedTable();
47141 tb = this.getBodyTable();
47142 index = colIndex - this.cm.getLockedCount();
47145 var rows = tb.rows;
47146 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
47147 for(var i = 0; i < stopIndex; i++){
47148 var cell = rows[i].childNodes[index].firstChild;
47149 maxWidth = Math.max(maxWidth, cell.scrollWidth);
47152 return maxWidth + /*margin for error in IE*/ 5;
47155 * Autofit a column to its content.
47156 * @param {Number} colIndex
47157 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
47159 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
47160 if(this.cm.isHidden(colIndex)){
47161 return; // can't calc a hidden column
47164 var cid = this.cm.getColumnId(colIndex);
47165 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
47166 if(this.grid.autoSizeHeaders){
47167 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
47170 var newWidth = this.calcColumnWidth(colIndex);
47171 this.cm.setColumnWidth(colIndex,
47172 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
47173 if(!suppressEvent){
47174 this.grid.fireEvent("columnresize", colIndex, newWidth);
47179 * Autofits all columns to their content and then expands to fit any extra space in the grid
47181 autoSizeColumns : function(){
47182 var cm = this.grid.colModel;
47183 var colCount = cm.getColumnCount();
47184 for(var i = 0; i < colCount; i++){
47185 this.autoSizeColumn(i, true, true);
47187 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
47190 this.updateColumns();
47196 * Autofits all columns to the grid's width proportionate with their current size
47197 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
47199 fitColumns : function(reserveScrollSpace){
47200 var cm = this.grid.colModel;
47201 var colCount = cm.getColumnCount();
47205 for (i = 0; i < colCount; i++){
47206 if(!cm.isHidden(i) && !cm.isFixed(i)){
47207 w = cm.getColumnWidth(i);
47213 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
47214 if(reserveScrollSpace){
47217 var frac = (avail - cm.getTotalWidth())/width;
47218 while (cols.length){
47221 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
47223 this.updateColumns();
47227 onRowSelect : function(rowIndex){
47228 var row = this.getRowComposite(rowIndex);
47229 row.addClass("x-grid-row-selected");
47232 onRowDeselect : function(rowIndex){
47233 var row = this.getRowComposite(rowIndex);
47234 row.removeClass("x-grid-row-selected");
47237 onCellSelect : function(row, col){
47238 var cell = this.getCell(row, col);
47240 Roo.fly(cell).addClass("x-grid-cell-selected");
47244 onCellDeselect : function(row, col){
47245 var cell = this.getCell(row, col);
47247 Roo.fly(cell).removeClass("x-grid-cell-selected");
47251 updateHeaderSortState : function(){
47252 var state = this.ds.getSortState();
47256 this.sortState = state;
47257 var sortColumn = this.cm.findColumnIndex(state.field);
47258 if(sortColumn != -1){
47259 var sortDir = state.direction;
47260 var sc = this.sortClasses;
47261 var hds = this.el.select(this.headerSelector).removeClass(sc);
47262 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
47266 handleHeaderClick : function(g, index){
47267 if(this.headersDisabled){
47270 var dm = g.dataSource, cm = g.colModel;
47271 if(!cm.isSortable(index)){
47275 dm.sort(cm.getDataIndex(index));
47279 destroy : function(){
47281 this.colMenu.removeAll();
47282 Roo.menu.MenuMgr.unregister(this.colMenu);
47283 this.colMenu.getEl().remove();
47284 delete this.colMenu;
47287 this.hmenu.removeAll();
47288 Roo.menu.MenuMgr.unregister(this.hmenu);
47289 this.hmenu.getEl().remove();
47292 if(this.grid.enableColumnMove){
47293 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47295 for(var dd in dds){
47296 if(!dds[dd].config.isTarget && dds[dd].dragElId){
47297 var elid = dds[dd].dragElId;
47299 Roo.get(elid).remove();
47300 } else if(dds[dd].config.isTarget){
47301 dds[dd].proxyTop.remove();
47302 dds[dd].proxyBottom.remove();
47305 if(Roo.dd.DDM.locationCache[dd]){
47306 delete Roo.dd.DDM.locationCache[dd];
47309 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47312 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
47313 this.bind(null, null);
47314 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
47317 handleLockChange : function(){
47318 this.refresh(true);
47321 onDenyColumnLock : function(){
47325 onDenyColumnHide : function(){
47329 handleHdMenuClick : function(item){
47330 var index = this.hdCtxIndex;
47331 var cm = this.cm, ds = this.ds;
47334 ds.sort(cm.getDataIndex(index), "ASC");
47337 ds.sort(cm.getDataIndex(index), "DESC");
47340 var lc = cm.getLockedCount();
47341 if(cm.getColumnCount(true) <= lc+1){
47342 this.onDenyColumnLock();
47346 cm.setLocked(index, true, true);
47347 cm.moveColumn(index, lc);
47348 this.grid.fireEvent("columnmove", index, lc);
47350 cm.setLocked(index, true);
47354 var lc = cm.getLockedCount();
47355 if((lc-1) != index){
47356 cm.setLocked(index, false, true);
47357 cm.moveColumn(index, lc-1);
47358 this.grid.fireEvent("columnmove", index, lc-1);
47360 cm.setLocked(index, false);
47364 index = cm.getIndexById(item.id.substr(4));
47366 if(item.checked && cm.getColumnCount(true) <= 1){
47367 this.onDenyColumnHide();
47370 cm.setHidden(index, item.checked);
47376 beforeColMenuShow : function(){
47377 var cm = this.cm, colCount = cm.getColumnCount();
47378 this.colMenu.removeAll();
47379 for(var i = 0; i < colCount; i++){
47380 this.colMenu.add(new Roo.menu.CheckItem({
47381 id: "col-"+cm.getColumnId(i),
47382 text: cm.getColumnHeader(i),
47383 checked: !cm.isHidden(i),
47389 handleHdCtx : function(g, index, e){
47391 var hd = this.getHeaderCell(index);
47392 this.hdCtxIndex = index;
47393 var ms = this.hmenu.items, cm = this.cm;
47394 ms.get("asc").setDisabled(!cm.isSortable(index));
47395 ms.get("desc").setDisabled(!cm.isSortable(index));
47396 if(this.grid.enableColLock !== false){
47397 ms.get("lock").setDisabled(cm.isLocked(index));
47398 ms.get("unlock").setDisabled(!cm.isLocked(index));
47400 this.hmenu.show(hd, "tl-bl");
47403 handleHdOver : function(e){
47404 var hd = this.findHeaderCell(e.getTarget());
47405 if(hd && !this.headersDisabled){
47406 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
47407 this.fly(hd).addClass("x-grid-hd-over");
47412 handleHdOut : function(e){
47413 var hd = this.findHeaderCell(e.getTarget());
47415 this.fly(hd).removeClass("x-grid-hd-over");
47419 handleSplitDblClick : function(e, t){
47420 var i = this.getCellIndex(t);
47421 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
47422 this.autoSizeColumn(i, true);
47427 render : function(){
47430 var colCount = cm.getColumnCount();
47432 if(this.grid.monitorWindowResize === true){
47433 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47435 var header = this.renderHeaders();
47436 var body = this.templates.body.apply({rows:""});
47437 var html = this.templates.master.apply({
47440 lockedHeader: header[0],
47444 //this.updateColumns();
47446 this.grid.getGridEl().dom.innerHTML = html;
47448 this.initElements();
47450 this.scroller.on("scroll", this.handleScroll, this);
47451 this.lockedBody.on("mousewheel", this.handleWheel, this);
47452 this.mainBody.on("mousewheel", this.handleWheel, this);
47454 this.mainHd.on("mouseover", this.handleHdOver, this);
47455 this.mainHd.on("mouseout", this.handleHdOut, this);
47456 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
47457 {delegate: "."+this.splitClass});
47459 this.lockedHd.on("mouseover", this.handleHdOver, this);
47460 this.lockedHd.on("mouseout", this.handleHdOut, this);
47461 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
47462 {delegate: "."+this.splitClass});
47464 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
47465 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47468 this.updateSplitters();
47470 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
47471 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47472 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47475 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
47476 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
47478 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
47479 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
47481 if(this.grid.enableColLock !== false){
47482 this.hmenu.add('-',
47483 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
47484 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
47487 if(this.grid.enableColumnHide !== false){
47489 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
47490 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
47491 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
47493 this.hmenu.add('-',
47494 {id:"columns", text: this.columnsText, menu: this.colMenu}
47497 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
47499 this.grid.on("headercontextmenu", this.handleHdCtx, this);
47502 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
47503 this.dd = new Roo.grid.GridDragZone(this.grid, {
47504 ddGroup : this.grid.ddGroup || 'GridDD'
47509 for(var i = 0; i < colCount; i++){
47510 if(cm.isHidden(i)){
47511 this.hideColumn(i);
47513 if(cm.config[i].align){
47514 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
47515 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
47519 this.updateHeaderSortState();
47521 this.beforeInitialResize();
47524 // two part rendering gives faster view to the user
47525 this.renderPhase2.defer(1, this);
47528 renderPhase2 : function(){
47529 // render the rows now
47531 if(this.grid.autoSizeColumns){
47532 this.autoSizeColumns();
47536 beforeInitialResize : function(){
47540 onColumnSplitterMoved : function(i, w){
47541 this.userResized = true;
47542 var cm = this.grid.colModel;
47543 cm.setColumnWidth(i, w, true);
47544 var cid = cm.getColumnId(i);
47545 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47546 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47547 this.updateSplitters();
47549 this.grid.fireEvent("columnresize", i, w);
47552 syncRowHeights : function(startIndex, endIndex){
47553 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
47554 startIndex = startIndex || 0;
47555 var mrows = this.getBodyTable().rows;
47556 var lrows = this.getLockedTable().rows;
47557 var len = mrows.length-1;
47558 endIndex = Math.min(endIndex || len, len);
47559 for(var i = startIndex; i <= endIndex; i++){
47560 var m = mrows[i], l = lrows[i];
47561 var h = Math.max(m.offsetHeight, l.offsetHeight);
47562 m.style.height = l.style.height = h + "px";
47567 layout : function(initialRender, is2ndPass){
47569 var auto = g.autoHeight;
47570 var scrollOffset = 16;
47571 var c = g.getGridEl(), cm = this.cm,
47572 expandCol = g.autoExpandColumn,
47574 //c.beginMeasure();
47576 if(!c.dom.offsetWidth){ // display:none?
47578 this.lockedWrap.show();
47579 this.mainWrap.show();
47584 var hasLock = this.cm.isLocked(0);
47586 var tbh = this.headerPanel.getHeight();
47587 var bbh = this.footerPanel.getHeight();
47590 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
47591 var newHeight = ch + c.getBorderWidth("tb");
47593 newHeight = Math.min(g.maxHeight, newHeight);
47595 c.setHeight(newHeight);
47599 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
47602 var s = this.scroller;
47604 var csize = c.getSize(true);
47606 this.el.setSize(csize.width, csize.height);
47608 this.headerPanel.setWidth(csize.width);
47609 this.footerPanel.setWidth(csize.width);
47611 var hdHeight = this.mainHd.getHeight();
47612 var vw = csize.width;
47613 var vh = csize.height - (tbh + bbh);
47617 var bt = this.getBodyTable();
47618 var ltWidth = hasLock ?
47619 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
47621 var scrollHeight = bt.offsetHeight;
47622 var scrollWidth = ltWidth + bt.offsetWidth;
47623 var vscroll = false, hscroll = false;
47625 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
47627 var lw = this.lockedWrap, mw = this.mainWrap;
47628 var lb = this.lockedBody, mb = this.mainBody;
47630 setTimeout(function(){
47631 var t = s.dom.offsetTop;
47632 var w = s.dom.clientWidth,
47633 h = s.dom.clientHeight;
47636 lw.setSize(ltWidth, h);
47638 mw.setLeftTop(ltWidth, t);
47639 mw.setSize(w-ltWidth, h);
47641 lb.setHeight(h-hdHeight);
47642 mb.setHeight(h-hdHeight);
47644 if(is2ndPass !== true && !gv.userResized && expandCol){
47645 // high speed resize without full column calculation
47647 var ci = cm.getIndexById(expandCol);
47649 ci = cm.findColumnIndex(expandCol);
47651 ci = Math.max(0, ci); // make sure it's got at least the first col.
47652 var expandId = cm.getColumnId(ci);
47653 var tw = cm.getTotalWidth(false);
47654 var currentWidth = cm.getColumnWidth(ci);
47655 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
47656 if(currentWidth != cw){
47657 cm.setColumnWidth(ci, cw, true);
47658 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47659 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47660 gv.updateSplitters();
47661 gv.layout(false, true);
47673 onWindowResize : function(){
47674 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
47680 appendFooter : function(parentEl){
47684 sortAscText : "Sort Ascending",
47685 sortDescText : "Sort Descending",
47686 lockText : "Lock Column",
47687 unlockText : "Unlock Column",
47688 columnsText : "Columns"
47692 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
47693 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
47694 this.proxy.el.addClass('x-grid3-col-dd');
47697 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
47698 handleMouseDown : function(e){
47702 callHandleMouseDown : function(e){
47703 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
47708 * Ext JS Library 1.1.1
47709 * Copyright(c) 2006-2007, Ext JS, LLC.
47711 * Originally Released Under LGPL - original licence link has changed is not relivant.
47714 * <script type="text/javascript">
47718 // This is a support class used internally by the Grid components
47719 Roo.grid.SplitDragZone = function(grid, hd, hd2){
47721 this.view = grid.getView();
47722 this.proxy = this.view.resizeProxy;
47723 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
47724 "gridSplitters" + this.grid.getGridEl().id, {
47725 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
47727 this.setHandleElId(Roo.id(hd));
47728 this.setOuterHandleElId(Roo.id(hd2));
47729 this.scroll = false;
47731 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
47732 fly: Roo.Element.fly,
47734 b4StartDrag : function(x, y){
47735 this.view.headersDisabled = true;
47736 this.proxy.setHeight(this.view.mainWrap.getHeight());
47737 var w = this.cm.getColumnWidth(this.cellIndex);
47738 var minw = Math.max(w-this.grid.minColumnWidth, 0);
47739 this.resetConstraints();
47740 this.setXConstraint(minw, 1000);
47741 this.setYConstraint(0, 0);
47742 this.minX = x - minw;
47743 this.maxX = x + 1000;
47745 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
47749 handleMouseDown : function(e){
47750 ev = Roo.EventObject.setEvent(e);
47751 var t = this.fly(ev.getTarget());
47752 if(t.hasClass("x-grid-split")){
47753 this.cellIndex = this.view.getCellIndex(t.dom);
47754 this.split = t.dom;
47755 this.cm = this.grid.colModel;
47756 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
47757 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
47762 endDrag : function(e){
47763 this.view.headersDisabled = false;
47764 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
47765 var diff = endX - this.startPos;
47766 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
47769 autoOffset : function(){
47770 this.setDelta(0,0);
47774 * Ext JS Library 1.1.1
47775 * Copyright(c) 2006-2007, Ext JS, LLC.
47777 * Originally Released Under LGPL - original licence link has changed is not relivant.
47780 * <script type="text/javascript">
47784 // This is a support class used internally by the Grid components
47785 Roo.grid.GridDragZone = function(grid, config){
47786 this.view = grid.getView();
47787 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
47788 if(this.view.lockedBody){
47789 this.setHandleElId(Roo.id(this.view.mainBody.dom));
47790 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
47792 this.scroll = false;
47794 this.ddel = document.createElement('div');
47795 this.ddel.className = 'x-grid-dd-wrap';
47798 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
47799 ddGroup : "GridDD",
47801 getDragData : function(e){
47802 var t = Roo.lib.Event.getTarget(e);
47803 var rowIndex = this.view.findRowIndex(t);
47804 if(rowIndex !== false){
47805 var sm = this.grid.selModel;
47806 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
47807 // sm.mouseDown(e, t);
47809 if (e.hasModifier()){
47810 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
47812 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
47817 onInitDrag : function(e){
47818 var data = this.dragData;
47819 this.ddel.innerHTML = this.grid.getDragDropText();
47820 this.proxy.update(this.ddel);
47821 // fire start drag?
47824 afterRepair : function(){
47825 this.dragging = false;
47828 getRepairXY : function(e, data){
47832 onEndDrag : function(data, e){
47836 onValidDrop : function(dd, e, id){
47841 beforeInvalidDrop : function(e, id){
47846 * Ext JS Library 1.1.1
47847 * Copyright(c) 2006-2007, Ext JS, LLC.
47849 * Originally Released Under LGPL - original licence link has changed is not relivant.
47852 * <script type="text/javascript">
47857 * @class Roo.grid.ColumnModel
47858 * @extends Roo.util.Observable
47859 * This is the default implementation of a ColumnModel used by the Grid. It defines
47860 * the columns in the grid.
47863 var colModel = new Roo.grid.ColumnModel([
47864 {header: "Ticker", width: 60, sortable: true, locked: true},
47865 {header: "Company Name", width: 150, sortable: true},
47866 {header: "Market Cap.", width: 100, sortable: true},
47867 {header: "$ Sales", width: 100, sortable: true, renderer: money},
47868 {header: "Employees", width: 100, sortable: true, resizable: false}
47873 * The config options listed for this class are options which may appear in each
47874 * individual column definition.
47875 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
47877 * @param {Object} config An Array of column config objects. See this class's
47878 * config objects for details.
47880 Roo.grid.ColumnModel = function(config){
47882 * The config passed into the constructor
47884 this.config = config;
47887 // if no id, create one
47888 // if the column does not have a dataIndex mapping,
47889 // map it to the order it is in the config
47890 for(var i = 0, len = config.length; i < len; i++){
47892 if(typeof c.dataIndex == "undefined"){
47895 if(typeof c.renderer == "string"){
47896 c.renderer = Roo.util.Format[c.renderer];
47898 if(typeof c.id == "undefined"){
47901 if(c.editor && c.editor.xtype){
47902 c.editor = Roo.factory(c.editor, Roo.grid);
47904 if(c.editor && c.editor.isFormField){
47905 c.editor = new Roo.grid.GridEditor(c.editor);
47907 this.lookup[c.id] = c;
47911 * The width of columns which have no width specified (defaults to 100)
47914 this.defaultWidth = 100;
47917 * Default sortable of columns which have no sortable specified (defaults to false)
47920 this.defaultSortable = false;
47924 * @event widthchange
47925 * Fires when the width of a column changes.
47926 * @param {ColumnModel} this
47927 * @param {Number} columnIndex The column index
47928 * @param {Number} newWidth The new width
47930 "widthchange": true,
47932 * @event headerchange
47933 * Fires when the text of a header changes.
47934 * @param {ColumnModel} this
47935 * @param {Number} columnIndex The column index
47936 * @param {Number} newText The new header text
47938 "headerchange": true,
47940 * @event hiddenchange
47941 * Fires when a column is hidden or "unhidden".
47942 * @param {ColumnModel} this
47943 * @param {Number} columnIndex The column index
47944 * @param {Boolean} hidden true if hidden, false otherwise
47946 "hiddenchange": true,
47948 * @event columnmoved
47949 * Fires when a column is moved.
47950 * @param {ColumnModel} this
47951 * @param {Number} oldIndex
47952 * @param {Number} newIndex
47954 "columnmoved" : true,
47956 * @event columlockchange
47957 * Fires when a column's locked state is changed
47958 * @param {ColumnModel} this
47959 * @param {Number} colIndex
47960 * @param {Boolean} locked true if locked
47962 "columnlockchange" : true
47964 Roo.grid.ColumnModel.superclass.constructor.call(this);
47966 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
47968 * @cfg {String} header The header text to display in the Grid view.
47971 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
47972 * {@link Roo.data.Record} definition from which to draw the column's value. If not
47973 * specified, the column's index is used as an index into the Record's data Array.
47976 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
47977 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
47980 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
47981 * Defaults to the value of the {@link #defaultSortable} property.
47982 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
47985 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
47988 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
47991 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
47994 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
47997 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
47998 * given the cell's data value. See {@link #setRenderer}. If not specified, the
47999 * default renderer uses the raw data value.
48002 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
48005 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
48009 * Returns the id of the column at the specified index.
48010 * @param {Number} index The column index
48011 * @return {String} the id
48013 getColumnId : function(index){
48014 return this.config[index].id;
48018 * Returns the column for a specified id.
48019 * @param {String} id The column id
48020 * @return {Object} the column
48022 getColumnById : function(id){
48023 return this.lookup[id];
48027 * Returns the index for a specified column id.
48028 * @param {String} id The column id
48029 * @return {Number} the index, or -1 if not found
48031 getIndexById : function(id){
48032 for(var i = 0, len = this.config.length; i < len; i++){
48033 if(this.config[i].id == id){
48040 * Returns the index for a specified column dataIndex.
48041 * @param {String} dataIndex The column dataIndex
48042 * @return {Number} the index, or -1 if not found
48045 findColumnIndex : function(dataIndex){
48046 for(var i = 0, len = this.config.length; i < len; i++){
48047 if(this.config[i].dataIndex == dataIndex){
48055 moveColumn : function(oldIndex, newIndex){
48056 var c = this.config[oldIndex];
48057 this.config.splice(oldIndex, 1);
48058 this.config.splice(newIndex, 0, c);
48059 this.dataMap = null;
48060 this.fireEvent("columnmoved", this, oldIndex, newIndex);
48063 isLocked : function(colIndex){
48064 return this.config[colIndex].locked === true;
48067 setLocked : function(colIndex, value, suppressEvent){
48068 if(this.isLocked(colIndex) == value){
48071 this.config[colIndex].locked = value;
48072 if(!suppressEvent){
48073 this.fireEvent("columnlockchange", this, colIndex, value);
48077 getTotalLockedWidth : function(){
48078 var totalWidth = 0;
48079 for(var i = 0; i < this.config.length; i++){
48080 if(this.isLocked(i) && !this.isHidden(i)){
48081 this.totalWidth += this.getColumnWidth(i);
48087 getLockedCount : function(){
48088 for(var i = 0, len = this.config.length; i < len; i++){
48089 if(!this.isLocked(i)){
48096 * Returns the number of columns.
48099 getColumnCount : function(visibleOnly){
48100 if(visibleOnly === true){
48102 for(var i = 0, len = this.config.length; i < len; i++){
48103 if(!this.isHidden(i)){
48109 return this.config.length;
48113 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
48114 * @param {Function} fn
48115 * @param {Object} scope (optional)
48116 * @return {Array} result
48118 getColumnsBy : function(fn, scope){
48120 for(var i = 0, len = this.config.length; i < len; i++){
48121 var c = this.config[i];
48122 if(fn.call(scope||this, c, i) === true){
48130 * Returns true if the specified column is sortable.
48131 * @param {Number} col The column index
48132 * @return {Boolean}
48134 isSortable : function(col){
48135 if(typeof this.config[col].sortable == "undefined"){
48136 return this.defaultSortable;
48138 return this.config[col].sortable;
48142 * Returns the rendering (formatting) function defined for the column.
48143 * @param {Number} col The column index.
48144 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
48146 getRenderer : function(col){
48147 if(!this.config[col].renderer){
48148 return Roo.grid.ColumnModel.defaultRenderer;
48150 return this.config[col].renderer;
48154 * Sets the rendering (formatting) function for a column.
48155 * @param {Number} col The column index
48156 * @param {Function} fn The function to use to process the cell's raw data
48157 * to return HTML markup for the grid view. The render function is called with
48158 * the following parameters:<ul>
48159 * <li>Data value.</li>
48160 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
48161 * <li>css A CSS style string to apply to the table cell.</li>
48162 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
48163 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
48164 * <li>Row index</li>
48165 * <li>Column index</li>
48166 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
48168 setRenderer : function(col, fn){
48169 this.config[col].renderer = fn;
48173 * Returns the width for the specified column.
48174 * @param {Number} col The column index
48177 getColumnWidth : function(col){
48178 return this.config[col].width || this.defaultWidth;
48182 * Sets the width for a column.
48183 * @param {Number} col The column index
48184 * @param {Number} width The new width
48186 setColumnWidth : function(col, width, suppressEvent){
48187 this.config[col].width = width;
48188 this.totalWidth = null;
48189 if(!suppressEvent){
48190 this.fireEvent("widthchange", this, col, width);
48195 * Returns the total width of all columns.
48196 * @param {Boolean} includeHidden True to include hidden column widths
48199 getTotalWidth : function(includeHidden){
48200 if(!this.totalWidth){
48201 this.totalWidth = 0;
48202 for(var i = 0, len = this.config.length; i < len; i++){
48203 if(includeHidden || !this.isHidden(i)){
48204 this.totalWidth += this.getColumnWidth(i);
48208 return this.totalWidth;
48212 * Returns the header for the specified column.
48213 * @param {Number} col The column index
48216 getColumnHeader : function(col){
48217 return this.config[col].header;
48221 * Sets the header for a column.
48222 * @param {Number} col The column index
48223 * @param {String} header The new header
48225 setColumnHeader : function(col, header){
48226 this.config[col].header = header;
48227 this.fireEvent("headerchange", this, col, header);
48231 * Returns the tooltip for the specified column.
48232 * @param {Number} col The column index
48235 getColumnTooltip : function(col){
48236 return this.config[col].tooltip;
48239 * Sets the tooltip for a column.
48240 * @param {Number} col The column index
48241 * @param {String} tooltip The new tooltip
48243 setColumnTooltip : function(col, tooltip){
48244 this.config[col].tooltip = tooltip;
48248 * Returns the dataIndex for the specified column.
48249 * @param {Number} col The column index
48252 getDataIndex : function(col){
48253 return this.config[col].dataIndex;
48257 * Sets the dataIndex for a column.
48258 * @param {Number} col The column index
48259 * @param {Number} dataIndex The new dataIndex
48261 setDataIndex : function(col, dataIndex){
48262 this.config[col].dataIndex = dataIndex;
48268 * Returns true if the cell is editable.
48269 * @param {Number} colIndex The column index
48270 * @param {Number} rowIndex The row index
48271 * @return {Boolean}
48273 isCellEditable : function(colIndex, rowIndex){
48274 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
48278 * Returns the editor defined for the cell/column.
48279 * return false or null to disable editing.
48280 * @param {Number} colIndex The column index
48281 * @param {Number} rowIndex The row index
48284 getCellEditor : function(colIndex, rowIndex){
48285 return this.config[colIndex].editor;
48289 * Sets if a column is editable.
48290 * @param {Number} col The column index
48291 * @param {Boolean} editable True if the column is editable
48293 setEditable : function(col, editable){
48294 this.config[col].editable = editable;
48299 * Returns true if the column is hidden.
48300 * @param {Number} colIndex The column index
48301 * @return {Boolean}
48303 isHidden : function(colIndex){
48304 return this.config[colIndex].hidden;
48309 * Returns true if the column width cannot be changed
48311 isFixed : function(colIndex){
48312 return this.config[colIndex].fixed;
48316 * Returns true if the column can be resized
48317 * @return {Boolean}
48319 isResizable : function(colIndex){
48320 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
48323 * Sets if a column is hidden.
48324 * @param {Number} colIndex The column index
48325 * @param {Boolean} hidden True if the column is hidden
48327 setHidden : function(colIndex, hidden){
48328 this.config[colIndex].hidden = hidden;
48329 this.totalWidth = null;
48330 this.fireEvent("hiddenchange", this, colIndex, hidden);
48334 * Sets the editor for a column.
48335 * @param {Number} col The column index
48336 * @param {Object} editor The editor object
48338 setEditor : function(col, editor){
48339 this.config[col].editor = editor;
48343 Roo.grid.ColumnModel.defaultRenderer = function(value){
48344 if(typeof value == "string" && value.length < 1){
48350 // Alias for backwards compatibility
48351 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
48354 * Ext JS Library 1.1.1
48355 * Copyright(c) 2006-2007, Ext JS, LLC.
48357 * Originally Released Under LGPL - original licence link has changed is not relivant.
48360 * <script type="text/javascript">
48364 * @class Roo.grid.AbstractSelectionModel
48365 * @extends Roo.util.Observable
48366 * Abstract base class for grid SelectionModels. It provides the interface that should be
48367 * implemented by descendant classes. This class should not be directly instantiated.
48370 Roo.grid.AbstractSelectionModel = function(){
48371 this.locked = false;
48372 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
48375 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
48376 /** @ignore Called by the grid automatically. Do not call directly. */
48377 init : function(grid){
48383 * Locks the selections.
48386 this.locked = true;
48390 * Unlocks the selections.
48392 unlock : function(){
48393 this.locked = false;
48397 * Returns true if the selections are locked.
48398 * @return {Boolean}
48400 isLocked : function(){
48401 return this.locked;
48405 * Ext JS Library 1.1.1
48406 * Copyright(c) 2006-2007, Ext JS, LLC.
48408 * Originally Released Under LGPL - original licence link has changed is not relivant.
48411 * <script type="text/javascript">
48414 * @extends Roo.grid.AbstractSelectionModel
48415 * @class Roo.grid.RowSelectionModel
48416 * The default SelectionModel used by {@link Roo.grid.Grid}.
48417 * It supports multiple selections and keyboard selection/navigation.
48419 * @param {Object} config
48421 Roo.grid.RowSelectionModel = function(config){
48422 Roo.apply(this, config);
48423 this.selections = new Roo.util.MixedCollection(false, function(o){
48428 this.lastActive = false;
48432 * @event selectionchange
48433 * Fires when the selection changes
48434 * @param {SelectionModel} this
48436 "selectionchange" : true,
48438 * @event afterselectionchange
48439 * Fires after the selection changes (eg. by key press or clicking)
48440 * @param {SelectionModel} this
48442 "afterselectionchange" : true,
48444 * @event beforerowselect
48445 * Fires when a row is selected being selected, return false to cancel.
48446 * @param {SelectionModel} this
48447 * @param {Number} rowIndex The selected index
48448 * @param {Boolean} keepExisting False if other selections will be cleared
48450 "beforerowselect" : true,
48453 * Fires when a row is selected.
48454 * @param {SelectionModel} this
48455 * @param {Number} rowIndex The selected index
48456 * @param {Roo.data.Record} r The record
48458 "rowselect" : true,
48460 * @event rowdeselect
48461 * Fires when a row is deselected.
48462 * @param {SelectionModel} this
48463 * @param {Number} rowIndex The selected index
48465 "rowdeselect" : true
48467 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
48468 this.locked = false;
48471 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
48473 * @cfg {Boolean} singleSelect
48474 * True to allow selection of only one row at a time (defaults to false)
48476 singleSelect : false,
48479 initEvents : function(){
48481 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
48482 this.grid.on("mousedown", this.handleMouseDown, this);
48483 }else{ // allow click to work like normal
48484 this.grid.on("rowclick", this.handleDragableRowClick, this);
48487 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
48488 "up" : function(e){
48490 this.selectPrevious(e.shiftKey);
48491 }else if(this.last !== false && this.lastActive !== false){
48492 var last = this.last;
48493 this.selectRange(this.last, this.lastActive-1);
48494 this.grid.getView().focusRow(this.lastActive);
48495 if(last !== false){
48499 this.selectFirstRow();
48501 this.fireEvent("afterselectionchange", this);
48503 "down" : function(e){
48505 this.selectNext(e.shiftKey);
48506 }else if(this.last !== false && this.lastActive !== false){
48507 var last = this.last;
48508 this.selectRange(this.last, this.lastActive+1);
48509 this.grid.getView().focusRow(this.lastActive);
48510 if(last !== false){
48514 this.selectFirstRow();
48516 this.fireEvent("afterselectionchange", this);
48521 var view = this.grid.view;
48522 view.on("refresh", this.onRefresh, this);
48523 view.on("rowupdated", this.onRowUpdated, this);
48524 view.on("rowremoved", this.onRemove, this);
48528 onRefresh : function(){
48529 var ds = this.grid.dataSource, i, v = this.grid.view;
48530 var s = this.selections;
48531 s.each(function(r){
48532 if((i = ds.indexOfId(r.id)) != -1){
48541 onRemove : function(v, index, r){
48542 this.selections.remove(r);
48546 onRowUpdated : function(v, index, r){
48547 if(this.isSelected(r)){
48548 v.onRowSelect(index);
48554 * @param {Array} records The records to select
48555 * @param {Boolean} keepExisting (optional) True to keep existing selections
48557 selectRecords : function(records, keepExisting){
48559 this.clearSelections();
48561 var ds = this.grid.dataSource;
48562 for(var i = 0, len = records.length; i < len; i++){
48563 this.selectRow(ds.indexOf(records[i]), true);
48568 * Gets the number of selected rows.
48571 getCount : function(){
48572 return this.selections.length;
48576 * Selects the first row in the grid.
48578 selectFirstRow : function(){
48583 * Select the last row.
48584 * @param {Boolean} keepExisting (optional) True to keep existing selections
48586 selectLastRow : function(keepExisting){
48587 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
48591 * Selects the row immediately following the last selected row.
48592 * @param {Boolean} keepExisting (optional) True to keep existing selections
48594 selectNext : function(keepExisting){
48595 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
48596 this.selectRow(this.last+1, keepExisting);
48597 this.grid.getView().focusRow(this.last);
48602 * Selects the row that precedes the last selected row.
48603 * @param {Boolean} keepExisting (optional) True to keep existing selections
48605 selectPrevious : function(keepExisting){
48607 this.selectRow(this.last-1, keepExisting);
48608 this.grid.getView().focusRow(this.last);
48613 * Returns the selected records
48614 * @return {Array} Array of selected records
48616 getSelections : function(){
48617 return [].concat(this.selections.items);
48621 * Returns the first selected record.
48624 getSelected : function(){
48625 return this.selections.itemAt(0);
48630 * Clears all selections.
48632 clearSelections : function(fast){
48633 if(this.locked) return;
48635 var ds = this.grid.dataSource;
48636 var s = this.selections;
48637 s.each(function(r){
48638 this.deselectRow(ds.indexOfId(r.id));
48642 this.selections.clear();
48649 * Selects all rows.
48651 selectAll : function(){
48652 if(this.locked) return;
48653 this.selections.clear();
48654 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
48655 this.selectRow(i, true);
48660 * Returns True if there is a selection.
48661 * @return {Boolean}
48663 hasSelection : function(){
48664 return this.selections.length > 0;
48668 * Returns True if the specified row is selected.
48669 * @param {Number/Record} record The record or index of the record to check
48670 * @return {Boolean}
48672 isSelected : function(index){
48673 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
48674 return (r && this.selections.key(r.id) ? true : false);
48678 * Returns True if the specified record id is selected.
48679 * @param {String} id The id of record to check
48680 * @return {Boolean}
48682 isIdSelected : function(id){
48683 return (this.selections.key(id) ? true : false);
48687 handleMouseDown : function(e, t){
48688 var view = this.grid.getView(), rowIndex;
48689 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
48692 if(e.shiftKey && this.last !== false){
48693 var last = this.last;
48694 this.selectRange(last, rowIndex, e.ctrlKey);
48695 this.last = last; // reset the last
48696 view.focusRow(rowIndex);
48698 var isSelected = this.isSelected(rowIndex);
48699 if(e.button !== 0 && isSelected){
48700 view.focusRow(rowIndex);
48701 }else if(e.ctrlKey && isSelected){
48702 this.deselectRow(rowIndex);
48703 }else if(!isSelected){
48704 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
48705 view.focusRow(rowIndex);
48708 this.fireEvent("afterselectionchange", this);
48711 handleDragableRowClick : function(grid, rowIndex, e)
48713 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
48714 this.selectRow(rowIndex, false);
48715 grid.view.focusRow(rowIndex);
48716 this.fireEvent("afterselectionchange", this);
48721 * Selects multiple rows.
48722 * @param {Array} rows Array of the indexes of the row to select
48723 * @param {Boolean} keepExisting (optional) True to keep existing selections
48725 selectRows : function(rows, keepExisting){
48727 this.clearSelections();
48729 for(var i = 0, len = rows.length; i < len; i++){
48730 this.selectRow(rows[i], true);
48735 * Selects a range of rows. All rows in between startRow and endRow are also selected.
48736 * @param {Number} startRow The index of the first row in the range
48737 * @param {Number} endRow The index of the last row in the range
48738 * @param {Boolean} keepExisting (optional) True to retain existing selections
48740 selectRange : function(startRow, endRow, keepExisting){
48741 if(this.locked) return;
48743 this.clearSelections();
48745 if(startRow <= endRow){
48746 for(var i = startRow; i <= endRow; i++){
48747 this.selectRow(i, true);
48750 for(var i = startRow; i >= endRow; i--){
48751 this.selectRow(i, true);
48757 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
48758 * @param {Number} startRow The index of the first row in the range
48759 * @param {Number} endRow The index of the last row in the range
48761 deselectRange : function(startRow, endRow, preventViewNotify){
48762 if(this.locked) return;
48763 for(var i = startRow; i <= endRow; i++){
48764 this.deselectRow(i, preventViewNotify);
48770 * @param {Number} row The index of the row to select
48771 * @param {Boolean} keepExisting (optional) True to keep existing selections
48773 selectRow : function(index, keepExisting, preventViewNotify){
48774 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
48775 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
48776 if(!keepExisting || this.singleSelect){
48777 this.clearSelections();
48779 var r = this.grid.dataSource.getAt(index);
48780 this.selections.add(r);
48781 this.last = this.lastActive = index;
48782 if(!preventViewNotify){
48783 this.grid.getView().onRowSelect(index);
48785 this.fireEvent("rowselect", this, index, r);
48786 this.fireEvent("selectionchange", this);
48792 * @param {Number} row The index of the row to deselect
48794 deselectRow : function(index, preventViewNotify){
48795 if(this.locked) return;
48796 if(this.last == index){
48799 if(this.lastActive == index){
48800 this.lastActive = false;
48802 var r = this.grid.dataSource.getAt(index);
48803 this.selections.remove(r);
48804 if(!preventViewNotify){
48805 this.grid.getView().onRowDeselect(index);
48807 this.fireEvent("rowdeselect", this, index);
48808 this.fireEvent("selectionchange", this);
48812 restoreLast : function(){
48814 this.last = this._last;
48819 acceptsNav : function(row, col, cm){
48820 return !cm.isHidden(col) && cm.isCellEditable(col, row);
48824 onEditorKey : function(field, e){
48825 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
48830 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
48832 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
48834 }else if(k == e.ENTER && !e.ctrlKey){
48838 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
48840 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
48842 }else if(k == e.ESC){
48846 g.startEditing(newCell[0], newCell[1]);
48851 * Ext JS Library 1.1.1
48852 * Copyright(c) 2006-2007, Ext JS, LLC.
48854 * Originally Released Under LGPL - original licence link has changed is not relivant.
48857 * <script type="text/javascript">
48860 * @class Roo.grid.CellSelectionModel
48861 * @extends Roo.grid.AbstractSelectionModel
48862 * This class provides the basic implementation for cell selection in a grid.
48864 * @param {Object} config The object containing the configuration of this model.
48866 Roo.grid.CellSelectionModel = function(config){
48867 Roo.apply(this, config);
48869 this.selection = null;
48873 * @event beforerowselect
48874 * Fires before a cell is selected.
48875 * @param {SelectionModel} this
48876 * @param {Number} rowIndex The selected row index
48877 * @param {Number} colIndex The selected cell index
48879 "beforecellselect" : true,
48881 * @event cellselect
48882 * Fires when a cell is selected.
48883 * @param {SelectionModel} this
48884 * @param {Number} rowIndex The selected row index
48885 * @param {Number} colIndex The selected cell index
48887 "cellselect" : true,
48889 * @event selectionchange
48890 * Fires when the active selection changes.
48891 * @param {SelectionModel} this
48892 * @param {Object} selection null for no selection or an object (o) with two properties
48894 <li>o.record: the record object for the row the selection is in</li>
48895 <li>o.cell: An array of [rowIndex, columnIndex]</li>
48898 "selectionchange" : true
48900 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
48903 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
48906 initEvents : function(){
48907 this.grid.on("mousedown", this.handleMouseDown, this);
48908 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
48909 var view = this.grid.view;
48910 view.on("refresh", this.onViewChange, this);
48911 view.on("rowupdated", this.onRowUpdated, this);
48912 view.on("beforerowremoved", this.clearSelections, this);
48913 view.on("beforerowsinserted", this.clearSelections, this);
48914 if(this.grid.isEditor){
48915 this.grid.on("beforeedit", this.beforeEdit, this);
48920 beforeEdit : function(e){
48921 this.select(e.row, e.column, false, true, e.record);
48925 onRowUpdated : function(v, index, r){
48926 if(this.selection && this.selection.record == r){
48927 v.onCellSelect(index, this.selection.cell[1]);
48932 onViewChange : function(){
48933 this.clearSelections(true);
48937 * Returns the currently selected cell,.
48938 * @return {Array} The selected cell (row, column) or null if none selected.
48940 getSelectedCell : function(){
48941 return this.selection ? this.selection.cell : null;
48945 * Clears all selections.
48946 * @param {Boolean} true to prevent the gridview from being notified about the change.
48948 clearSelections : function(preventNotify){
48949 var s = this.selection;
48951 if(preventNotify !== true){
48952 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
48954 this.selection = null;
48955 this.fireEvent("selectionchange", this, null);
48960 * Returns true if there is a selection.
48961 * @return {Boolean}
48963 hasSelection : function(){
48964 return this.selection ? true : false;
48968 handleMouseDown : function(e, t){
48969 var v = this.grid.getView();
48970 if(this.isLocked()){
48973 var row = v.findRowIndex(t);
48974 var cell = v.findCellIndex(t);
48975 if(row !== false && cell !== false){
48976 this.select(row, cell);
48982 * @param {Number} rowIndex
48983 * @param {Number} collIndex
48985 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
48986 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
48987 this.clearSelections();
48988 r = r || this.grid.dataSource.getAt(rowIndex);
48991 cell : [rowIndex, colIndex]
48993 if(!preventViewNotify){
48994 var v = this.grid.getView();
48995 v.onCellSelect(rowIndex, colIndex);
48996 if(preventFocus !== true){
48997 v.focusCell(rowIndex, colIndex);
49000 this.fireEvent("cellselect", this, rowIndex, colIndex);
49001 this.fireEvent("selectionchange", this, this.selection);
49006 isSelectable : function(rowIndex, colIndex, cm){
49007 return !cm.isHidden(colIndex);
49011 handleKeyDown : function(e){
49012 if(!e.isNavKeyPress()){
49015 var g = this.grid, s = this.selection;
49018 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
49020 this.select(cell[0], cell[1]);
49025 var walk = function(row, col, step){
49026 return g.walkCells(row, col, step, sm.isSelectable, sm);
49028 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
49034 newCell = walk(r, c-1, -1);
49036 newCell = walk(r, c+1, 1);
49040 newCell = walk(r+1, c, 1);
49043 newCell = walk(r-1, c, -1);
49046 newCell = walk(r, c+1, 1);
49049 newCell = walk(r, c-1, -1);
49052 if(g.isEditor && !g.editing){
49053 g.startEditing(r, c);
49060 this.select(newCell[0], newCell[1]);
49065 acceptsNav : function(row, col, cm){
49066 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49069 onEditorKey : function(field, e){
49070 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49073 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49075 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49078 }else if(k == e.ENTER && !e.ctrlKey){
49081 }else if(k == e.ESC){
49085 g.startEditing(newCell[0], newCell[1]);
49090 * Ext JS Library 1.1.1
49091 * Copyright(c) 2006-2007, Ext JS, LLC.
49093 * Originally Released Under LGPL - original licence link has changed is not relivant.
49096 * <script type="text/javascript">
49100 * @class Roo.grid.EditorGrid
49101 * @extends Roo.grid.Grid
49102 * Class for creating and editable grid.
49103 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49104 * The container MUST have some type of size defined for the grid to fill. The container will be
49105 * automatically set to position relative if it isn't already.
49106 * @param {Object} dataSource The data model to bind to
49107 * @param {Object} colModel The column model with info about this grid's columns
49109 Roo.grid.EditorGrid = function(container, config){
49110 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
49111 this.getGridEl().addClass("xedit-grid");
49113 if(!this.selModel){
49114 this.selModel = new Roo.grid.CellSelectionModel();
49117 this.activeEditor = null;
49121 * @event beforeedit
49122 * Fires before cell editing is triggered. The edit event object has the following properties <br />
49123 * <ul style="padding:5px;padding-left:16px;">
49124 * <li>grid - This grid</li>
49125 * <li>record - The record being edited</li>
49126 * <li>field - The field name being edited</li>
49127 * <li>value - The value for the field being edited.</li>
49128 * <li>row - The grid row index</li>
49129 * <li>column - The grid column index</li>
49130 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
49132 * @param {Object} e An edit event (see above for description)
49134 "beforeedit" : true,
49137 * Fires after a cell is edited. <br />
49138 * <ul style="padding:5px;padding-left:16px;">
49139 * <li>grid - This grid</li>
49140 * <li>record - The record being edited</li>
49141 * <li>field - The field name being edited</li>
49142 * <li>value - The value being set</li>
49143 * <li>originalValue - The original value for the field, before the edit.</li>
49144 * <li>row - The grid row index</li>
49145 * <li>column - The grid column index</li>
49147 * @param {Object} e An edit event (see above for description)
49149 "afteredit" : true,
49151 * @event validateedit
49152 * Fires after a cell is edited, but before the value is set in the record.
49153 * You can use this to modify the value being set in the field, Return false
49154 * to cancel the change. The edit event object has the following properties <br />
49155 * <ul style="padding:5px;padding-left:16px;">
49156 * <li>editor - This editor</li>
49157 * <li>grid - This grid</li>
49158 * <li>record - The record being edited</li>
49159 * <li>field - The field name being edited</li>
49160 * <li>value - The value being set</li>
49161 * <li>originalValue - The original value for the field, before the edit.</li>
49162 * <li>row - The grid row index</li>
49163 * <li>column - The grid column index</li>
49164 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
49166 * @param {Object} e An edit event (see above for description)
49168 "validateedit" : true
49170 this.on("bodyscroll", this.stopEditing, this);
49171 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
49174 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
49176 * @cfg {Number} clicksToEdit
49177 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
49184 trackMouseOver: false, // causes very odd FF errors
49186 onCellDblClick : function(g, row, col){
49187 this.startEditing(row, col);
49190 onEditComplete : function(ed, value, startValue){
49191 this.editing = false;
49192 this.activeEditor = null;
49193 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
49195 var field = this.colModel.getDataIndex(ed.col);
49200 originalValue: startValue,
49207 if(String(value) !== String(startValue)){
49209 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
49210 r.set(field, e.value);
49211 delete e.cancel; //?? why!!!
49212 this.fireEvent("afteredit", e);
49215 this.fireEvent("afteredit", e); // always fir it!
49217 this.view.focusCell(ed.row, ed.col);
49221 * Starts editing the specified for the specified row/column
49222 * @param {Number} rowIndex
49223 * @param {Number} colIndex
49225 startEditing : function(row, col){
49226 this.stopEditing();
49227 if(this.colModel.isCellEditable(col, row)){
49228 this.view.ensureVisible(row, col, true);
49229 var r = this.dataSource.getAt(row);
49230 var field = this.colModel.getDataIndex(col);
49235 value: r.data[field],
49240 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
49241 this.editing = true;
49242 var ed = this.colModel.getCellEditor(col, row);
49248 ed.render(ed.parentEl || document.body);
49251 (function(){ // complex but required for focus issues in safari, ie and opera
49255 ed.on("complete", this.onEditComplete, this, {single: true});
49256 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
49257 this.activeEditor = ed;
49258 var v = r.data[field];
49259 ed.startEdit(this.view.getCell(row, col), v);
49260 }).defer(50, this);
49266 * Stops any active editing
49268 stopEditing : function(){
49269 if(this.activeEditor){
49270 this.activeEditor.completeEdit();
49272 this.activeEditor = null;
49276 * Ext JS Library 1.1.1
49277 * Copyright(c) 2006-2007, Ext JS, LLC.
49279 * Originally Released Under LGPL - original licence link has changed is not relivant.
49282 * <script type="text/javascript">
49285 // private - not really -- you end up using it !
49286 // This is a support class used internally by the Grid components
49289 * @class Roo.grid.GridEditor
49290 * @extends Roo.Editor
49291 * Class for creating and editable grid elements.
49292 * @param {Object} config any settings (must include field)
49294 Roo.grid.GridEditor = function(field, config){
49295 if (!config && field.field) {
49297 field = Roo.factory(config.field, Roo.form);
49299 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
49300 field.monitorTab = false;
49303 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
49306 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
49309 alignment: "tl-tl",
49312 cls: "x-small-editor x-grid-editor",
49317 * Ext JS Library 1.1.1
49318 * Copyright(c) 2006-2007, Ext JS, LLC.
49320 * Originally Released Under LGPL - original licence link has changed is not relivant.
49323 * <script type="text/javascript">
49328 Roo.grid.PropertyRecord = Roo.data.Record.create([
49329 {name:'name',type:'string'}, 'value'
49333 Roo.grid.PropertyStore = function(grid, source){
49335 this.store = new Roo.data.Store({
49336 recordType : Roo.grid.PropertyRecord
49338 this.store.on('update', this.onUpdate, this);
49340 this.setSource(source);
49342 Roo.grid.PropertyStore.superclass.constructor.call(this);
49347 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
49348 setSource : function(o){
49350 this.store.removeAll();
49353 if(this.isEditableValue(o[k])){
49354 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
49357 this.store.loadRecords({records: data}, {}, true);
49360 onUpdate : function(ds, record, type){
49361 if(type == Roo.data.Record.EDIT){
49362 var v = record.data['value'];
49363 var oldValue = record.modified['value'];
49364 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
49365 this.source[record.id] = v;
49367 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
49374 getProperty : function(row){
49375 return this.store.getAt(row);
49378 isEditableValue: function(val){
49379 if(val && val instanceof Date){
49381 }else if(typeof val == 'object' || typeof val == 'function'){
49387 setValue : function(prop, value){
49388 this.source[prop] = value;
49389 this.store.getById(prop).set('value', value);
49392 getSource : function(){
49393 return this.source;
49397 Roo.grid.PropertyColumnModel = function(grid, store){
49400 g.PropertyColumnModel.superclass.constructor.call(this, [
49401 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
49402 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
49404 this.store = store;
49405 this.bselect = Roo.DomHelper.append(document.body, {
49406 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
49407 {tag: 'option', value: 'true', html: 'true'},
49408 {tag: 'option', value: 'false', html: 'false'}
49411 Roo.id(this.bselect);
49414 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
49415 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
49416 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
49417 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
49418 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
49420 this.renderCellDelegate = this.renderCell.createDelegate(this);
49421 this.renderPropDelegate = this.renderProp.createDelegate(this);
49424 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
49428 valueText : 'Value',
49430 dateFormat : 'm/j/Y',
49433 renderDate : function(dateVal){
49434 return dateVal.dateFormat(this.dateFormat);
49437 renderBool : function(bVal){
49438 return bVal ? 'true' : 'false';
49441 isCellEditable : function(colIndex, rowIndex){
49442 return colIndex == 1;
49445 getRenderer : function(col){
49447 this.renderCellDelegate : this.renderPropDelegate;
49450 renderProp : function(v){
49451 return this.getPropertyName(v);
49454 renderCell : function(val){
49456 if(val instanceof Date){
49457 rv = this.renderDate(val);
49458 }else if(typeof val == 'boolean'){
49459 rv = this.renderBool(val);
49461 return Roo.util.Format.htmlEncode(rv);
49464 getPropertyName : function(name){
49465 var pn = this.grid.propertyNames;
49466 return pn && pn[name] ? pn[name] : name;
49469 getCellEditor : function(colIndex, rowIndex){
49470 var p = this.store.getProperty(rowIndex);
49471 var n = p.data['name'], val = p.data['value'];
49473 if(typeof(this.grid.customEditors[n]) == 'string'){
49474 return this.editors[this.grid.customEditors[n]];
49476 if(typeof(this.grid.customEditors[n]) != 'undefined'){
49477 return this.grid.customEditors[n];
49479 if(val instanceof Date){
49480 return this.editors['date'];
49481 }else if(typeof val == 'number'){
49482 return this.editors['number'];
49483 }else if(typeof val == 'boolean'){
49484 return this.editors['boolean'];
49486 return this.editors['string'];
49492 * @class Roo.grid.PropertyGrid
49493 * @extends Roo.grid.EditorGrid
49494 * This class represents the interface of a component based property grid control.
49495 * <br><br>Usage:<pre><code>
49496 var grid = new Roo.grid.PropertyGrid("my-container-id", {
49504 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49505 * The container MUST have some type of size defined for the grid to fill. The container will be
49506 * automatically set to position relative if it isn't already.
49507 * @param {Object} config A config object that sets properties on this grid.
49509 Roo.grid.PropertyGrid = function(container, config){
49510 config = config || {};
49511 var store = new Roo.grid.PropertyStore(this);
49512 this.store = store;
49513 var cm = new Roo.grid.PropertyColumnModel(this, store);
49514 store.store.sort('name', 'ASC');
49515 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
49518 enableColLock:false,
49519 enableColumnMove:false,
49521 trackMouseOver: false,
49524 this.getGridEl().addClass('x-props-grid');
49525 this.lastEditRow = null;
49526 this.on('columnresize', this.onColumnResize, this);
49529 * @event beforepropertychange
49530 * Fires before a property changes (return false to stop?)
49531 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49532 * @param {String} id Record Id
49533 * @param {String} newval New Value
49534 * @param {String} oldval Old Value
49536 "beforepropertychange": true,
49538 * @event propertychange
49539 * Fires after a property changes
49540 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49541 * @param {String} id Record Id
49542 * @param {String} newval New Value
49543 * @param {String} oldval Old Value
49545 "propertychange": true
49547 this.customEditors = this.customEditors || {};
49549 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
49552 * @cfg {Object} customEditors map of colnames=> custom editors.
49553 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
49554 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
49555 * false disables editing of the field.
49559 * @cfg {Object} propertyNames map of property Names to their displayed value
49562 render : function(){
49563 Roo.grid.PropertyGrid.superclass.render.call(this);
49564 this.autoSize.defer(100, this);
49567 autoSize : function(){
49568 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
49570 this.view.fitColumns();
49574 onColumnResize : function(){
49575 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
49579 * Sets the data for the Grid
49580 * accepts a Key => Value object of all the elements avaiable.
49581 * @param {Object} data to appear in grid.
49583 setSource : function(source){
49584 this.store.setSource(source);
49588 * Gets all the data from the grid.
49589 * @return {Object} data data stored in grid
49591 getSource : function(){
49592 return this.store.getSource();
49596 * Ext JS Library 1.1.1
49597 * Copyright(c) 2006-2007, Ext JS, LLC.
49599 * Originally Released Under LGPL - original licence link has changed is not relivant.
49602 * <script type="text/javascript">
49606 * @class Roo.LoadMask
49607 * A simple utility class for generically masking elements while loading data. If the element being masked has
49608 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
49609 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
49610 * element's UpdateManager load indicator and will be destroyed after the initial load.
49612 * Create a new LoadMask
49613 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
49614 * @param {Object} config The config object
49616 Roo.LoadMask = function(el, config){
49617 this.el = Roo.get(el);
49618 Roo.apply(this, config);
49620 this.store.on('beforeload', this.onBeforeLoad, this);
49621 this.store.on('load', this.onLoad, this);
49622 this.store.on('loadexception', this.onLoad, this);
49623 this.removeMask = false;
49625 var um = this.el.getUpdateManager();
49626 um.showLoadIndicator = false; // disable the default indicator
49627 um.on('beforeupdate', this.onBeforeLoad, this);
49628 um.on('update', this.onLoad, this);
49629 um.on('failure', this.onLoad, this);
49630 this.removeMask = true;
49634 Roo.LoadMask.prototype = {
49636 * @cfg {Boolean} removeMask
49637 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
49638 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
49641 * @cfg {String} msg
49642 * The text to display in a centered loading message box (defaults to 'Loading...')
49644 msg : 'Loading...',
49646 * @cfg {String} msgCls
49647 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
49649 msgCls : 'x-mask-loading',
49652 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
49658 * Disables the mask to prevent it from being displayed
49660 disable : function(){
49661 this.disabled = true;
49665 * Enables the mask so that it can be displayed
49667 enable : function(){
49668 this.disabled = false;
49672 onLoad : function(){
49673 this.el.unmask(this.removeMask);
49677 onBeforeLoad : function(){
49678 if(!this.disabled){
49679 this.el.mask(this.msg, this.msgCls);
49684 destroy : function(){
49686 this.store.un('beforeload', this.onBeforeLoad, this);
49687 this.store.un('load', this.onLoad, this);
49688 this.store.un('loadexception', this.onLoad, this);
49690 var um = this.el.getUpdateManager();
49691 um.un('beforeupdate', this.onBeforeLoad, this);
49692 um.un('update', this.onLoad, this);
49693 um.un('failure', this.onLoad, this);
49698 * Ext JS Library 1.1.1
49699 * Copyright(c) 2006-2007, Ext JS, LLC.
49701 * Originally Released Under LGPL - original licence link has changed is not relivant.
49704 * <script type="text/javascript">
49706 Roo.XTemplate = function(){
49707 Roo.XTemplate.superclass.constructor.apply(this, arguments);
49710 s = ['<tpl>', s, '</tpl>'].join('');
49712 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
49714 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
49715 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
49716 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
49720 while(m = s.match(re)){
49721 var m2 = m[0].match(nameRe);
49722 var m3 = m[0].match(ifRe);
49723 var m4 = m[0].match(execRe);
49724 var exp = null, fn = null, exec = null;
49725 var name = m2 && m2[1] ? m2[1] : '';
49727 exp = m3 && m3[1] ? m3[1] : null;
49729 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
49733 exp = m4 && m4[1] ? m4[1] : null;
49735 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
49740 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
49741 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
49742 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
49752 s = s.replace(m[0], '{xtpl'+ id + '}');
49755 for(var i = tpls.length-1; i >= 0; --i){
49756 this.compileTpl(tpls[i]);
49758 this.master = tpls[tpls.length-1];
49761 Roo.extend(Roo.XTemplate, Roo.Template, {
49763 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
49765 applySubTemplate : function(id, values, parent){
49766 var t = this.tpls[id];
49767 if(t.test && !t.test.call(this, values, parent)){
49770 if(t.exec && t.exec.call(this, values, parent)){
49773 var vs = t.target ? t.target.call(this, values, parent) : values;
49774 parent = t.target ? values : parent;
49775 if(t.target && vs instanceof Array){
49777 for(var i = 0, len = vs.length; i < len; i++){
49778 buf[buf.length] = t.compiled.call(this, vs[i], parent);
49780 return buf.join('');
49782 return t.compiled.call(this, vs, parent);
49785 compileTpl : function(tpl){
49786 var fm = Roo.util.Format;
49787 var useF = this.disableFormats !== true;
49788 var sep = Roo.isGecko ? "+" : ",";
49789 var fn = function(m, name, format, args){
49790 if(name.substr(0, 4) == 'xtpl'){
49791 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
49794 if(name.indexOf('.') != -1){
49797 v = "values['" + name + "']";
49799 if(format && useF){
49800 args = args ? ',' + args : "";
49801 if(format.substr(0, 5) != "this."){
49802 format = "fm." + format + '(';
49804 format = 'this.call("'+ format.substr(5) + '", ';
49808 args= ''; format = "("+v+" === undefined ? '' : ";
49810 return "'"+ sep + format + v + args + ")"+sep+"'";
49813 // branched to use + in gecko and [].join() in others
49815 body = "tpl.compiled = function(values, parent){ return '" +
49816 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
49819 body = ["tpl.compiled = function(values, parent){ return ['"];
49820 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
49821 body.push("'].join('');};");
49822 body = body.join('');
49824 /** eval:var:zzzzzzz */
49829 applyTemplate : function(values){
49830 return this.master.compiled.call(this, values, {});
49834 apply : function(){
49835 return this.applyTemplate.apply(this, arguments);
49838 compile : function(){return this;}
49841 Roo.XTemplate.from = function(el){
49842 el = Roo.getDom(el);
49843 return new Roo.XTemplate(el.value || el.innerHTML);
49845 * Original code for Roojs - LGPL
49846 * <script type="text/javascript">
49850 * @class Roo.XComponent
49851 * A delayed Element creator...
49853 * Mypart.xyx = new Roo.XComponent({
49855 parent : 'Mypart.xyz', // empty == document.element.!!
49859 disabled : function() {}
49861 tree : function() { // return an tree of xtype declared components
49865 xtype : 'NestedLayoutPanel',
49870 * @extends Roo.util.Observable
49872 * @param cfg {Object} configuration of component
49875 Roo.XComponent = function(cfg) {
49876 Roo.apply(this, cfg);
49880 * Fires when this the componnt is built
49881 * @param {Roo.XComponent} c the component
49885 * @event buildcomplete
49886 * Fires on the top level element when all elements have been built
49887 * @param {Roo.XComponent} c the top level component.
49889 'buildcomplete' : true,
49893 Roo.XComponent.register(this);
49894 this.modules = false;
49895 this.el = false; // where the layout goes..
49899 Roo.extend(Roo.XComponent, Roo.util.Observable, {
49902 * The created element (with Roo.factory())
49903 * @type {Roo.Layout}
49909 * for BC - use el in new code
49910 * @type {Roo.Layout}
49916 * for BC - use el in new code
49917 * @type {Roo.Layout}
49922 * @cfg {Function|boolean} disabled
49923 * If this module is disabled by some rule, return true from the funtion
49928 * @cfg {String} parent
49929 * Name of parent element which it get xtype added to..
49934 * @cfg {String} order
49935 * Used to set the order in which elements are created (usefull for multiple tabs)
49940 * @cfg {String} name
49941 * String to display while loading.
49945 * @cfg {Array} items
49946 * A single item array - the first element is the root of the tree..
49947 * It's done this way to stay compatible with the Xtype system...
49955 Roo.apply(Roo.XComponent, {
49958 * @property buildCompleted
49959 * True when the builder has completed building the interface.
49962 buildCompleted : false,
49965 * @property topModule
49966 * the upper most module - uses document.element as it's constructor.
49973 * @property modules
49974 * array of modules to be created by registration system.
49975 * @type Roo.XComponent
49982 * Register components to be built later.
49984 * This solves the following issues
49985 * - Building is not done on page load, but after an authentication process has occured.
49986 * - Interface elements are registered on page load
49987 * - Parent Interface elements may not be loaded before child, so this handles that..
49994 module : 'Pman.Tab.projectMgr',
49996 parent : 'Pman.layout',
49997 disabled : false, // or use a function..
50000 * * @param {Object} details about module
50002 register : function(obj) {
50003 this.modules.push(obj);
50007 * convert a string to an object..
50011 toObject : function(str)
50013 if (!str || typeof(str) == 'object') {
50016 var ar = str.split('.');
50020 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
50022 throw "Module not found : " + str;
50024 Roo.each(ar, function(e) {
50025 if (typeof(o[e]) == 'undefined') {
50026 throw "Module not found : " + str;
50036 * move modules into their correct place in the tree..
50039 preBuild : function ()
50042 Roo.each(this.modules , function (obj)
50044 obj.parent = this.toObject(obj.parent);
50047 this.topModule = obj;
50051 if (!obj.parent.modules) {
50052 obj.parent.modules = new Roo.util.MixedCollection(false,
50053 function(o) { return o.order + '' }
50057 obj.parent.modules.add(obj);
50062 * make a list of modules to build.
50063 * @return {Array} list of modules.
50066 buildOrder : function()
50069 var cmp = function(a,b) {
50070 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
50073 if (!this.topModule || !this.topModule.modules) {
50074 throw "No top level modules to build";
50077 // make a flat list in order of modules to build.
50078 var mods = [ this.topModule ];
50081 // add modules to their parents..
50082 var addMod = function(m) {
50083 // console.log(m.modKey);
50087 m.modules.keySort('ASC', cmp );
50088 m.modules.each(addMod);
50090 // not sure if this is used any more..
50092 m.finalize.name = m.name + " (clean up) ";
50093 mods.push(m.finalize);
50097 this.topModule.modules.keySort('ASC', cmp );
50098 this.topModule.modules.each(addMod);
50103 * Build the registered modules.
50104 * @param {Object} parent element.
50105 * @param {Function} optional method to call after module has been added.
50113 var mods = this.buildOrder();
50115 //this.allmods = mods;
50116 //console.log(mods);
50118 if (!mods.length) { // should not happen
50119 throw "NO modules!!!";
50124 // flash it up as modal - so we store the mask!?
50125 Roo.MessageBox.show({ title: 'loading' });
50126 Roo.MessageBox.show({
50127 title: "Please wait...",
50128 msg: "Building Interface...",
50135 var total = mods.length;
50138 var progressRun = function() {
50139 if (!mods.length) {
50140 console.log('hide?');
50141 Roo.MessageBox.hide();
50142 _this.topModule.fireEvent('buildcomplete', _this.topModule);
50146 var m = mods.shift();
50148 if (typeof(m) == 'function') { // not sure if this is supported any more..
50150 return progressRun.defer(10, _this);
50153 Roo.MessageBox.updateProgress(
50154 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
50156 (m.name ? (' - ' + m.name) : '')
50161 var disabled = (typeof(m.disabled) == 'function') ?
50162 m.disabled.call(m.module.disabled) : m.disabled;
50166 return progressRun(); // we do not update the display!
50170 // it's a top level one..
50171 var layoutbase = new Ext.BorderLayout(document.body, {
50177 tabPosition: 'top',
50178 //resizeTabs: true,
50179 alwaysShowTabs: true,
50183 var tree = m.tree();
50184 tree.region = 'center';
50185 m.el = layoutbase.addxtype(tree);
50187 m.layout = m.panel.layout;
50188 return progressRun.defer(10, _this);
50191 var tree = m.tree();
50192 tree.region = tree.region || m.region;
50193 m.el = m.parent.el.addxtype(tree);
50194 m.fireEvent('built', m);
50196 m.layout = m.panel.layout;
50197 progressRun.defer(10, _this);
50200 progressRun.defer(1, _this);
50210 //<script type="text/javascript">
50215 * @extends Roo.LayoutDialog
50216 * A generic Login Dialog..... - only one needed in theory!?!?
50218 * Fires XComponent builder on success...
50221 * username,password, lang = for login actions.
50222 * check = 1 for periodic checking that sesion is valid.
50223 * passwordRequest = email request password
50224 * logout = 1 = to logout
50226 * Affects: (this id="????" elements)
50227 * loading (removed) (used to indicate application is loading)
50228 * loading-mask (hides) (used to hide application when it's building loading)
50234 * Myapp.login = Roo.Login({
50250 Roo.Login = function(cfg)
50253 'refreshed' : true,
50256 Roo.apply(this,cfg);
50258 Roo.onReady(function() {
50264 Roo.Login.superclass.constructor.call(this, this);
50265 //this.addxtype(this.items[0]);
50271 Roo.extend(Roo.Login, Roo.LayoutDialog, {
50274 * @cfg {String} method
50275 * Method used to query for login details.
50280 * @cfg {String} url
50281 * URL to query login data. - eg. baseURL + '/Login.php'
50287 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
50292 * @property checkFails
50293 * Number of times we have attempted to get authentication check, and failed.
50298 * @property intervalID
50299 * The window interval that does the constant login checking.
50305 onLoad : function() // called on page load...
50309 if (Roo.get('loading')) { // clear any loading indicator..
50310 Roo.get('loading').remove();
50313 //this.switchLang('en'); // set the language to english..
50316 success: function(response, opts) { // check successfull...
50318 var res = this.processResponse(response);
50319 this.checkFails =0;
50320 if (!res.success) { // error!
50321 this.checkFails = 5;
50322 //console.log('call failure');
50323 return this.failure(response,opts);
50326 if (!res.data.id) { // id=0 == login failure.
50327 return this.show();
50331 //console.log(success);
50332 this.fillAuth(res.data);
50333 this.checkFails =0;
50334 Roo.XComponent.build();
50336 failure : this.show
50342 check: function(cfg) // called every so often to refresh cookie etc..
50344 if (cfg.again) { // could be undefined..
50347 this.checkFails = 0;
50350 if (this.sending) {
50351 if ( this.checkFails > 4) {
50352 Roo.MessageBox.alert("Error",
50353 "Error getting authentication status. - try reloading, or wait a while", function() {
50354 _this.sending = false;
50359 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
50362 this.sending = true;
50369 method: this.method,
50370 success: cfg.success || this.success,
50371 failure : cfg.failure || this.failure,
50381 window.onbeforeunload = function() { }; // false does not work for IE..
50391 failure : function() {
50392 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
50393 document.location = document.location.toString() + '?ts=' + Math.random();
50397 success : function() {
50398 _this.user = false;
50399 this.checkFails =0;
50401 document.location = document.location.toString() + '?ts=' + Math.random();
50408 processResponse : function (response)
50412 res = Roo.decode(response.responseText);
50414 if (typeof(res) != 'object') {
50415 res = { success : false, errorMsg : res, errors : true };
50417 if (typeof(res.success) == 'undefined') {
50418 res.success = false;
50422 res = { success : false, errorMsg : response.responseText, errors : true };
50427 success : function(response, opts) // check successfull...
50429 this.sending = false;
50430 var res = this.processResponse(response);
50431 if (!res.success) {
50432 return this.failure(response, opts);
50434 if (!res.data || !res.data.id) {
50435 return this.failure(response,opts);
50437 //console.log(res);
50438 this.fillAuth(res.data);
50440 this.checkFails =0;
50445 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
50447 this.authUser = -1;
50448 this.sending = false;
50449 var res = this.processResponse(response);
50450 //console.log(res);
50451 if ( this.checkFails > 2) {
50453 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
50454 "Error getting authentication status. - try reloading");
50457 opts.callCfg.again = true;
50458 this.check.defer(1000, this, [ opts.callCfg ]);
50464 fillAuth: function(au) {
50465 this.startAuthCheck();
50466 this.authUserId = au.id;
50467 this.authUser = au;
50468 this.lastChecked = new Date();
50469 this.fireEvent('refreshed', au);
50470 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
50471 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
50472 au.lang = au.lang || 'en';
50473 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
50474 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
50475 this.switchLang(au.lang );
50478 // open system... - -on setyp..
50479 if (this.authUserId < 0) {
50480 Roo.MessageBox.alert("Warning",
50481 "This is an open system - please set up a admin user with a password.");
50484 //Pman.onload(); // which should do nothing if it's a re-auth result...
50489 startAuthCheck : function() // starter for timeout checking..
50491 if (this.intervalID) { // timer already in place...
50495 this.intervalID = window.setInterval(function() {
50496 _this.check(false);
50497 }, 120000); // every 120 secs = 2mins..
50503 switchLang : function (lang)
50505 _T = typeof(_T) == 'undefined' ? false : _T;
50506 if (!_T || !lang.length) {
50510 if (!_T && lang != 'en') {
50511 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
50515 if (typeof(_T.en) == 'undefined') {
50517 Roo.apply(_T.en, _T);
50520 if (typeof(_T[lang]) == 'undefined') {
50521 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
50526 Roo.apply(_T, _T[lang]);
50527 // just need to set the text values for everything...
50529 /* this will not work ...
50533 function formLabel(name, val) {
50534 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
50537 formLabel('password', "Password"+':');
50538 formLabel('username', "Email Address"+':');
50539 formLabel('lang', "Language"+':');
50540 this.dialog.setTitle("Login");
50541 this.dialog.buttons[0].setText("Forgot Password");
50542 this.dialog.buttons[1].setText("Login");
50561 collapsible: false,
50563 center: { // needed??
50566 // tabPosition: 'top',
50569 alwaysShowTabs: false
50573 show : function(dlg)
50575 //console.log(this);
50576 this.form = this.layout.getRegion('center').activePanel.form;
50577 this.form.dialog = dlg;
50578 this.buttons[0].form = this.form;
50579 this.buttons[0].dialog = dlg
50580 this.buttons[1].form = this.form;
50581 this.buttons[1].dialog = dlg;
50583 //this.resizeToLogo.defer(1000,this);
50584 // this is all related to resizing for logos..
50585 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
50587 // this.resizeToLogo.defer(1000,this);
50590 //var w = Ext.lib.Dom.getViewWidth() - 100;
50591 //var h = Ext.lib.Dom.getViewHeight() - 100;
50592 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
50594 if (this.disabled) {
50599 if (this.user.id < 0) { // used for inital setup situations.
50603 if (this.intervalID) {
50604 // remove the timer
50605 window.clearInterval(this.intervalID);
50606 this.intervalID = false;
50610 if (Roo.get('loading')) {
50611 Roo.get('loading').remove();
50613 if (Roo.get('loading-mask')) {
50614 Roo.get('loading-mask').hide();
50617 //incomming._node = tnode;
50619 //this.dialog.modal = !modal;
50620 //this.dialog.show();
50624 this.form.setValues({
50625 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
50626 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
50629 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
50630 if (this.form.findField('username').getValue().length > 0 ){
50631 this.form.findField('password').focus();
50633 this.form.findField('username').focus();
50641 xtype : 'ContentPanel',
50653 style : 'margin: 10px;',
50656 actionfailed : function(f, act) {
50657 // form can return { errors: .... }
50659 //act.result.errors // invalid form element list...
50660 //act.result.errorMsg// invalid form element list...
50662 this.dialog.el.unmask();
50663 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
50664 "Login failed - communication error - try again.");
50667 actioncomplete: function(re, act) {
50669 Roo.state.Manager.set(
50670 this.dialog.realm + '.username',
50671 this.findField('username').getValue()
50673 Roo.state.Manager.set(
50674 this.dialog.realm + '.lang',
50675 this.findField('lang').getValue()
50678 this.dialog.fillAuth(act.result.data);
50680 this.dialog.hide();
50682 if (Roo.get('loading-mask')) {
50683 Roo.get('loading-mask').show();
50685 Roo.XComponent.build();
50693 xtype : 'TextField',
50695 fieldLabel: "Email Address",
50698 autoCreate : {tag: "input", type: "text", size: "20"}
50701 xtype : 'TextField',
50703 fieldLabel: "Password",
50704 inputType: 'password',
50707 autoCreate : {tag: "input", type: "text", size: "20"},
50709 specialkey : function(e,ev) {
50710 if (ev.keyCode == 13) {
50711 this.form.dialog.el.mask("Logging in");
50712 this.form.doAction('submit', {
50713 url: this.form.dialog.url,
50714 method: this.form.dialog.method,
50721 xtype : 'ComboBox',
50723 fieldLabel: "Language",
50726 xtype : 'SimpleStore',
50727 fields: ['lang', 'ldisp'],
50729 [ 'en', 'English' ],
50730 [ 'zh_HK' , '\u7E41\u4E2D' ],
50731 [ 'zh_CN', '\u7C21\u4E2D' ]
50735 valueField : 'lang',
50736 hiddenName: 'lang',
50738 displayField:'ldisp',
50742 triggerAction: 'all',
50743 emptyText:'Select a Language...',
50744 selectOnFocus:true,
50746 select : function(cb, rec, ix) {
50747 this.form.switchLang(rec.data.lang);
50763 text : "Forgot Password",
50765 click : function() {
50766 //console.log(this);
50767 var n = this.form.findField('username').getValue();
50769 Roo.MessageBox.alert("Error", "Fill in your email address");
50773 url: this.dialog.url,
50777 method: this.dialog.method,
50778 success: function(response, opts) { // check successfull...
50780 var res = this.dialog.processResponse(response);
50781 if (!res.success) { // error!
50782 Roo.MessageBox.alert("Error" ,
50783 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
50786 Roo.MessageBox.alert("Notice" ,
50787 "Please check you email for the Password Reset message");
50789 failure : function() {
50790 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
50803 click : function () {
50805 this.dialog.el.mask("Logging in");
50806 this.form.doAction('submit', {
50807 url: this.dialog.url,
50808 method: this.dialog.method