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)),
575 * Selects a single element as a Roo Element
576 * This is about as close as you can get to jQuery's $('do crazy stuff')
577 * @param {String} selector The selector/xpath query
578 * @param {Node} root (optional) The start of the query (defaults to document).
579 * @return {Roo.Element}
581 selectNode : function(selector, root)
583 var node = Roo.DomQuery.selectNode(selector,root);
584 return node ? Roo.get(node) : false;
592 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
593 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
596 * Ext JS Library 1.1.1
597 * Copyright(c) 2006-2007, Ext JS, LLC.
599 * Originally Released Under LGPL - original licence link has changed is not relivant.
602 * <script type="text/javascript">
606 // wrappedn so fnCleanup is not in global scope...
608 function fnCleanUp() {
609 var p = Function.prototype;
610 delete p.createSequence;
612 delete p.createDelegate;
613 delete p.createCallback;
614 delete p.createInterceptor;
616 window.detachEvent("onunload", fnCleanUp);
618 window.attachEvent("onunload", fnCleanUp);
625 * These functions are available on every Function object (any JavaScript function).
627 Roo.apply(Function.prototype, {
629 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
630 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
631 * Will create a function that is bound to those 2 args.
632 * @return {Function} The new function
634 createCallback : function(/*args...*/){
635 // make args available, in function below
636 var args = arguments;
639 return method.apply(window, args);
644 * Creates a delegate (callback) that sets the scope to obj.
645 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
646 * Will create a function that is automatically scoped to this.
647 * @param {Object} obj (optional) The object for which the scope is set
648 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
649 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
650 * if a number the args are inserted at the specified position
651 * @return {Function} The new function
653 createDelegate : function(obj, args, appendArgs){
656 var callArgs = args || arguments;
657 if(appendArgs === true){
658 callArgs = Array.prototype.slice.call(arguments, 0);
659 callArgs = callArgs.concat(args);
660 }else if(typeof appendArgs == "number"){
661 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
662 var applyArgs = [appendArgs, 0].concat(args); // create method call params
663 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
665 return method.apply(obj || window, callArgs);
670 * Calls this function after the number of millseconds specified.
671 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
672 * @param {Object} obj (optional) The object for which the scope is set
673 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
674 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
675 * if a number the args are inserted at the specified position
676 * @return {Number} The timeout id that can be used with clearTimeout
678 defer : function(millis, obj, args, appendArgs){
679 var fn = this.createDelegate(obj, args, appendArgs);
681 return setTimeout(fn, millis);
687 * Create a combined function call sequence of the original function + the passed function.
688 * The resulting function returns the results of the original function.
689 * The passed fcn is called with the parameters of the original function
690 * @param {Function} fcn The function to sequence
691 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
692 * @return {Function} The new function
694 createSequence : function(fcn, scope){
695 if(typeof fcn != "function"){
700 var retval = method.apply(this || window, arguments);
701 fcn.apply(scope || this || window, arguments);
707 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
708 * The resulting function returns the results of the original function.
709 * The passed fcn is called with the parameters of the original function.
711 * @param {Function} fcn The function to call before the original
712 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
713 * @return {Function} The new function
715 createInterceptor : function(fcn, scope){
716 if(typeof fcn != "function"){
723 if(fcn.apply(scope || this || window, arguments) === false){
726 return method.apply(this || window, arguments);
732 * Ext JS Library 1.1.1
733 * Copyright(c) 2006-2007, Ext JS, LLC.
735 * Originally Released Under LGPL - original licence link has changed is not relivant.
738 * <script type="text/javascript">
741 Roo.applyIf(String, {
746 * Escapes the passed string for ' and \
747 * @param {String} string The string to escape
748 * @return {String} The escaped string
751 escape : function(string) {
752 return string.replace(/('|\\)/g, "\\$1");
756 * Pads the left side of a string with a specified character. This is especially useful
757 * for normalizing number and date strings. Example usage:
759 var s = String.leftPad('123', 5, '0');
760 // s now contains the string: '00123'
762 * @param {String} string The original string
763 * @param {Number} size The total length of the output string
764 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
765 * @return {String} The padded string
768 leftPad : function (val, size, ch) {
769 var result = new String(val);
770 if(ch === null || ch === undefined || ch === '') {
773 while (result.length < size) {
774 result = ch + result;
780 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
781 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
783 var cls = 'my-class', text = 'Some text';
784 var s = String.format('<div class="{0}">{1}</div>', cls, text);
785 // s now contains the string: '<div class="my-class">Some text</div>'
787 * @param {String} string The tokenized string to be formatted
788 * @param {String} value1 The value to replace token {0}
789 * @param {String} value2 Etc...
790 * @return {String} The formatted string
793 format : function(format){
794 var args = Array.prototype.slice.call(arguments, 1);
795 return format.replace(/\{(\d+)\}/g, function(m, i){
796 return Roo.util.Format.htmlEncode(args[i]);
802 * Utility function that allows you to easily switch a string between two alternating values. The passed value
803 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
804 * they are already different, the first value passed in is returned. Note that this method returns the new value
805 * but does not change the current string.
807 // alternate sort directions
808 sort = sort.toggle('ASC', 'DESC');
810 // instead of conditional logic:
811 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
813 * @param {String} value The value to compare to the current string
814 * @param {String} other The new value to use if the string already equals the first value passed in
815 * @return {String} The new value
818 String.prototype.toggle = function(value, other){
819 return this == value ? other : value;
822 * Ext JS Library 1.1.1
823 * Copyright(c) 2006-2007, Ext JS, LLC.
825 * Originally Released Under LGPL - original licence link has changed is not relivant.
828 * <script type="text/javascript">
834 Roo.applyIf(Number.prototype, {
836 * Checks whether or not the current number is within a desired range. If the number is already within the
837 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
838 * exceeded. Note that this method returns the constrained value but does not change the current number.
839 * @param {Number} min The minimum number in the range
840 * @param {Number} max The maximum number in the range
841 * @return {Number} The constrained value if outside the range, otherwise the current value
843 constrain : function(min, max){
844 return Math.min(Math.max(this, min), max);
848 * Ext JS Library 1.1.1
849 * Copyright(c) 2006-2007, Ext JS, LLC.
851 * Originally Released Under LGPL - original licence link has changed is not relivant.
854 * <script type="text/javascript">
859 Roo.applyIf(Array.prototype, {
861 * Checks whether or not the specified object exists in the array.
862 * @param {Object} o The object to check for
863 * @return {Number} The index of o in the array (or -1 if it is not found)
865 indexOf : function(o){
866 for (var i = 0, len = this.length; i < len; i++){
867 if(this[i] == o) return i;
873 * Removes the specified object from the array. If the object is not found nothing happens.
874 * @param {Object} o The object to remove
876 remove : function(o){
877 var index = this.indexOf(o);
879 this.splice(index, 1);
883 * Map (JS 1.6 compatibility)
884 * @param {Function} function to call
888 var len = this.length >>> 0;
889 if (typeof fun != "function")
890 throw new TypeError();
892 var res = new Array(len);
893 var thisp = arguments[1];
894 for (var i = 0; i < len; i++)
897 res[i] = fun.call(thisp, this[i], i, this);
908 * Ext JS Library 1.1.1
909 * Copyright(c) 2006-2007, Ext JS, LLC.
911 * Originally Released Under LGPL - original licence link has changed is not relivant.
914 * <script type="text/javascript">
920 * The date parsing and format syntax is a subset of
921 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
922 * supported will provide results equivalent to their PHP versions.
924 * Following is the list of all currently supported formats:
927 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
929 Format Output Description
930 ------ ---------- --------------------------------------------------------------
931 d 10 Day of the month, 2 digits with leading zeros
932 D Wed A textual representation of a day, three letters
933 j 10 Day of the month without leading zeros
934 l Wednesday A full textual representation of the day of the week
935 S th English ordinal day of month suffix, 2 chars (use with j)
936 w 3 Numeric representation of the day of the week
937 z 9 The julian date, or day of the year (0-365)
938 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
939 F January A full textual representation of the month
940 m 01 Numeric representation of a month, with leading zeros
941 M Jan Month name abbreviation, three letters
942 n 1 Numeric representation of a month, without leading zeros
943 t 31 Number of days in the given month
944 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
945 Y 2007 A full numeric representation of a year, 4 digits
946 y 07 A two digit representation of a year
947 a pm Lowercase Ante meridiem and Post meridiem
948 A PM Uppercase Ante meridiem and Post meridiem
949 g 3 12-hour format of an hour without leading zeros
950 G 15 24-hour format of an hour without leading zeros
951 h 03 12-hour format of an hour with leading zeros
952 H 15 24-hour format of an hour with leading zeros
953 i 05 Minutes with leading zeros
954 s 01 Seconds, with leading zeros
955 O -0600 Difference to Greenwich time (GMT) in hours
956 T CST Timezone setting of the machine running the code
957 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
960 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
962 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
963 document.write(dt.format('Y-m-d')); //2007-01-10
964 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
965 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
968 * Here are some standard date/time patterns that you might find helpful. They
969 * are not part of the source of Date.js, but to use them you can simply copy this
970 * block of code into any script that is included after Date.js and they will also become
971 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
974 ISO8601Long:"Y-m-d H:i:s",
975 ISO8601Short:"Y-m-d",
977 LongDate: "l, F d, Y",
978 FullDateTime: "l, F d, Y g:i:s A",
982 SortableDateTime: "Y-m-d\\TH:i:s",
983 UniversalSortableDateTime: "Y-m-d H:i:sO",
991 document.write(dt.format(Date.patterns.ShortDate));
996 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
997 * They generate precompiled functions from date formats instead of parsing and
998 * processing the pattern every time you format a date. These functions are available
999 * on every Date object (any javascript function).
1001 * The original article and download are here:
1002 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1009 Returns the number of milliseconds between this date and date
1010 @param {Date} date (optional) Defaults to now
1011 @return {Number} The diff in milliseconds
1012 @member Date getElapsed
1014 Date.prototype.getElapsed = function(date) {
1015 return Math.abs((date || new Date()).getTime()-this.getTime());
1017 // was in date file..
1021 Date.parseFunctions = {count:0};
1023 Date.parseRegexes = [];
1025 Date.formatFunctions = {count:0};
1028 Date.prototype.dateFormat = function(format) {
1029 if (Date.formatFunctions[format] == null) {
1030 Date.createNewFormat(format);
1032 var func = Date.formatFunctions[format];
1033 return this[func]();
1038 * Formats a date given the supplied format string
1039 * @param {String} format The format string
1040 * @return {String} The formatted date
1043 Date.prototype.format = Date.prototype.dateFormat;
1046 Date.createNewFormat = function(format) {
1047 var funcName = "format" + Date.formatFunctions.count++;
1048 Date.formatFunctions[format] = funcName;
1049 var code = "Date.prototype." + funcName + " = function(){return ";
1050 var special = false;
1052 for (var i = 0; i < format.length; ++i) {
1053 ch = format.charAt(i);
1054 if (!special && ch == "\\") {
1059 code += "'" + String.escape(ch) + "' + ";
1062 code += Date.getFormatCode(ch);
1065 /** eval:var:zzzzzzzzzzzzz */
1066 eval(code.substring(0, code.length - 3) + ";}");
1070 Date.getFormatCode = function(character) {
1071 switch (character) {
1073 return "String.leftPad(this.getDate(), 2, '0') + ";
1075 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1077 return "this.getDate() + ";
1079 return "Date.dayNames[this.getDay()] + ";
1081 return "this.getSuffix() + ";
1083 return "this.getDay() + ";
1085 return "this.getDayOfYear() + ";
1087 return "this.getWeekOfYear() + ";
1089 return "Date.monthNames[this.getMonth()] + ";
1091 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1093 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1095 return "(this.getMonth() + 1) + ";
1097 return "this.getDaysInMonth() + ";
1099 return "(this.isLeapYear() ? 1 : 0) + ";
1101 return "this.getFullYear() + ";
1103 return "('' + this.getFullYear()).substring(2, 4) + ";
1105 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1107 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1109 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1111 return "this.getHours() + ";
1113 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1115 return "String.leftPad(this.getHours(), 2, '0') + ";
1117 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1119 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1121 return "this.getGMTOffset() + ";
1123 return "this.getTimezone() + ";
1125 return "(this.getTimezoneOffset() * -60) + ";
1127 return "'" + String.escape(character) + "' + ";
1132 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1133 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1134 * the date format that is not specified will default to the current date value for that part. Time parts can also
1135 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1136 * string or the parse operation will fail.
1139 //dt = Fri May 25 2007 (current date)
1140 var dt = new Date();
1142 //dt = Thu May 25 2006 (today's month/day in 2006)
1143 dt = Date.parseDate("2006", "Y");
1145 //dt = Sun Jan 15 2006 (all date parts specified)
1146 dt = Date.parseDate("2006-1-15", "Y-m-d");
1148 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1149 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1151 * @param {String} input The unparsed date as a string
1152 * @param {String} format The format the date is in
1153 * @return {Date} The parsed date
1156 Date.parseDate = function(input, format) {
1157 if (Date.parseFunctions[format] == null) {
1158 Date.createParser(format);
1160 var func = Date.parseFunctions[format];
1161 return Date[func](input);
1166 Date.createParser = function(format) {
1167 var funcName = "parse" + Date.parseFunctions.count++;
1168 var regexNum = Date.parseRegexes.length;
1169 var currentGroup = 1;
1170 Date.parseFunctions[format] = funcName;
1172 var code = "Date." + funcName + " = function(input){\n"
1173 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1174 + "var d = new Date();\n"
1175 + "y = d.getFullYear();\n"
1176 + "m = d.getMonth();\n"
1177 + "d = d.getDate();\n"
1178 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1179 + "if (results && results.length > 0) {";
1182 var special = false;
1184 for (var i = 0; i < format.length; ++i) {
1185 ch = format.charAt(i);
1186 if (!special && ch == "\\") {
1191 regex += String.escape(ch);
1194 var obj = Date.formatCodeToRegex(ch, currentGroup);
1195 currentGroup += obj.g;
1197 if (obj.g && obj.c) {
1203 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1204 + "{v = new Date(y, m, d, h, i, s);}\n"
1205 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1206 + "{v = new Date(y, m, d, h, i);}\n"
1207 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1208 + "{v = new Date(y, m, d, h);}\n"
1209 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1210 + "{v = new Date(y, m, d);}\n"
1211 + "else if (y >= 0 && m >= 0)\n"
1212 + "{v = new Date(y, m);}\n"
1213 + "else if (y >= 0)\n"
1214 + "{v = new Date(y);}\n"
1215 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1216 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1217 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1220 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1221 /** eval:var:zzzzzzzzzzzzz */
1226 Date.formatCodeToRegex = function(character, currentGroup) {
1227 switch (character) {
1231 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1234 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1235 s:"(\\d{1,2})"}; // day of month without leading zeroes
1238 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1239 s:"(\\d{2})"}; // day of month with leading zeroes
1243 s:"(?:" + Date.dayNames.join("|") + ")"};
1247 s:"(?:st|nd|rd|th)"};
1262 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1263 s:"(" + Date.monthNames.join("|") + ")"};
1266 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1267 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1270 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1271 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1274 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1275 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1286 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1290 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1291 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1295 c:"if (results[" + currentGroup + "] == 'am') {\n"
1296 + "if (h == 12) { h = 0; }\n"
1297 + "} else { if (h < 12) { h += 12; }}",
1301 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1302 + "if (h == 12) { h = 0; }\n"
1303 + "} else { if (h < 12) { h += 12; }}",
1308 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1309 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1313 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1314 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1317 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1321 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1326 "o = results[", currentGroup, "];\n",
1327 "var sn = o.substring(0,1);\n", // get + / - sign
1328 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1329 "var mn = o.substring(3,5) % 60;\n", // get minutes
1330 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1331 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1337 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1340 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1341 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1342 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1346 s:String.escape(character)};
1351 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1352 * @return {String} The abbreviated timezone name (e.g. 'CST')
1354 Date.prototype.getTimezone = function() {
1355 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1359 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1360 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1362 Date.prototype.getGMTOffset = function() {
1363 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1364 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1365 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1369 * Get the numeric day number of the year, adjusted for leap year.
1370 * @return {Number} 0 through 364 (365 in leap years)
1372 Date.prototype.getDayOfYear = function() {
1374 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1375 for (var i = 0; i < this.getMonth(); ++i) {
1376 num += Date.daysInMonth[i];
1378 return num + this.getDate() - 1;
1382 * Get the string representation of the numeric week number of the year
1383 * (equivalent to the format specifier 'W').
1384 * @return {String} '00' through '52'
1386 Date.prototype.getWeekOfYear = function() {
1387 // Skip to Thursday of this week
1388 var now = this.getDayOfYear() + (4 - this.getDay());
1389 // Find the first Thursday of the year
1390 var jan1 = new Date(this.getFullYear(), 0, 1);
1391 var then = (7 - jan1.getDay() + 4);
1392 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1396 * Whether or not the current date is in a leap year.
1397 * @return {Boolean} True if the current date is in a leap year, else false
1399 Date.prototype.isLeapYear = function() {
1400 var year = this.getFullYear();
1401 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1405 * Get the first 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.getFirstDayOfMonth()]); //output: 'Monday'
1413 * @return {Number} The day number (0-6)
1415 Date.prototype.getFirstDayOfMonth = function() {
1416 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1417 return (day < 0) ? (day + 7) : day;
1421 * Get the last day of the current month, adjusted for leap year. The returned value
1422 * is the numeric day index within the week (0-6) which can be used in conjunction with
1423 * the {@link #monthNames} array to retrieve the textual day name.
1426 var dt = new Date('1/10/2007');
1427 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1429 * @return {Number} The day number (0-6)
1431 Date.prototype.getLastDayOfMonth = function() {
1432 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1433 return (day < 0) ? (day + 7) : day;
1438 * Get the first date of this date's month
1441 Date.prototype.getFirstDateOfMonth = function() {
1442 return new Date(this.getFullYear(), this.getMonth(), 1);
1446 * Get the last date of this date's month
1449 Date.prototype.getLastDateOfMonth = function() {
1450 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1453 * Get the number of days in the current month, adjusted for leap year.
1454 * @return {Number} The number of days in the month
1456 Date.prototype.getDaysInMonth = function() {
1457 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1458 return Date.daysInMonth[this.getMonth()];
1462 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1463 * @return {String} 'st, 'nd', 'rd' or 'th'
1465 Date.prototype.getSuffix = function() {
1466 switch (this.getDate()) {
1483 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1486 * An array of textual month names.
1487 * Override these values for international dates, for example...
1488 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1507 * An array of textual day names.
1508 * Override these values for international dates, for example...
1509 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1525 Date.monthNumbers = {
1540 * Creates and returns a new Date instance with the exact same date value as the called instance.
1541 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1542 * variable will also be changed. When the intention is to create a new variable that will not
1543 * modify the original instance, you should create a clone.
1545 * Example of correctly cloning a date:
1548 var orig = new Date('10/1/2006');
1551 document.write(orig); //returns 'Thu Oct 05 2006'!
1554 var orig = new Date('10/1/2006');
1555 var copy = orig.clone();
1557 document.write(orig); //returns 'Thu Oct 01 2006'
1559 * @return {Date} The new Date instance
1561 Date.prototype.clone = function() {
1562 return new Date(this.getTime());
1566 * Clears any time information from this date
1567 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1568 @return {Date} this or the clone
1570 Date.prototype.clearTime = function(clone){
1572 return this.clone().clearTime();
1577 this.setMilliseconds(0);
1582 // safari setMonth is broken
1584 Date.brokenSetMonth = Date.prototype.setMonth;
1585 Date.prototype.setMonth = function(num){
1587 var n = Math.ceil(-num);
1588 var back_year = Math.ceil(n/12);
1589 var month = (n % 12) ? 12 - n % 12 : 0 ;
1590 this.setFullYear(this.getFullYear() - back_year);
1591 return Date.brokenSetMonth.call(this, month);
1593 return Date.brokenSetMonth.apply(this, arguments);
1598 /** Date interval constant
1602 /** Date interval constant
1606 /** Date interval constant
1610 /** Date interval constant
1614 /** Date interval constant
1618 /** Date interval constant
1622 /** Date interval constant
1628 * Provides a convenient method of performing basic date arithmetic. This method
1629 * does not modify the Date instance being called - it creates and returns
1630 * a new Date instance containing the resulting date value.
1635 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1636 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1638 //Negative values will subtract correctly:
1639 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1640 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1642 //You can even chain several calls together in one line!
1643 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1644 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1647 * @param {String} interval A valid date interval enum value
1648 * @param {Number} value The amount to add to the current date
1649 * @return {Date} The new Date instance
1651 Date.prototype.add = function(interval, value){
1652 var d = this.clone();
1653 if (!interval || value === 0) return d;
1654 switch(interval.toLowerCase()){
1656 d.setMilliseconds(this.getMilliseconds() + value);
1659 d.setSeconds(this.getSeconds() + value);
1662 d.setMinutes(this.getMinutes() + value);
1665 d.setHours(this.getHours() + value);
1668 d.setDate(this.getDate() + value);
1671 var day = this.getDate();
1673 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1676 d.setMonth(this.getMonth() + value);
1679 d.setFullYear(this.getFullYear() + value);
1685 * Ext JS Library 1.1.1
1686 * Copyright(c) 2006-2007, Ext JS, LLC.
1688 * Originally Released Under LGPL - original licence link has changed is not relivant.
1691 * <script type="text/javascript">
1695 getViewWidth : function(full) {
1696 return full ? this.getDocumentWidth() : this.getViewportWidth();
1699 getViewHeight : function(full) {
1700 return full ? this.getDocumentHeight() : this.getViewportHeight();
1703 getDocumentHeight: function() {
1704 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1705 return Math.max(scrollHeight, this.getViewportHeight());
1708 getDocumentWidth: function() {
1709 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1710 return Math.max(scrollWidth, this.getViewportWidth());
1713 getViewportHeight: function() {
1714 var height = self.innerHeight;
1715 var mode = document.compatMode;
1717 if ((mode || Roo.isIE) && !Roo.isOpera) {
1718 height = (mode == "CSS1Compat") ?
1719 document.documentElement.clientHeight :
1720 document.body.clientHeight;
1726 getViewportWidth: function() {
1727 var width = self.innerWidth;
1728 var mode = document.compatMode;
1730 if (mode || Roo.isIE) {
1731 width = (mode == "CSS1Compat") ?
1732 document.documentElement.clientWidth :
1733 document.body.clientWidth;
1738 isAncestor : function(p, c) {
1745 if (p.contains && !Roo.isSafari) {
1746 return p.contains(c);
1747 } else if (p.compareDocumentPosition) {
1748 return !!(p.compareDocumentPosition(c) & 16);
1750 var parent = c.parentNode;
1755 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1758 parent = parent.parentNode;
1764 getRegion : function(el) {
1765 return Roo.lib.Region.getRegion(el);
1768 getY : function(el) {
1769 return this.getXY(el)[1];
1772 getX : function(el) {
1773 return this.getXY(el)[0];
1776 getXY : function(el) {
1777 var p, pe, b, scroll, bd = document.body;
1778 el = Roo.getDom(el);
1779 var fly = Roo.lib.AnimBase.fly;
1780 if (el.getBoundingClientRect) {
1781 b = el.getBoundingClientRect();
1782 scroll = fly(document).getScroll();
1783 return [b.left + scroll.left, b.top + scroll.top];
1789 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1796 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1803 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1804 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1811 if (p != el && pe.getStyle('overflow') != 'visible') {
1819 if (Roo.isSafari && hasAbsolute) {
1824 if (Roo.isGecko && !hasAbsolute) {
1826 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1827 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1831 while (p && p != bd) {
1832 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1844 setXY : function(el, xy) {
1845 el = Roo.fly(el, '_setXY');
1847 var pts = el.translatePoints(xy);
1848 if (xy[0] !== false) {
1849 el.dom.style.left = pts.left + "px";
1851 if (xy[1] !== false) {
1852 el.dom.style.top = pts.top + "px";
1856 setX : function(el, x) {
1857 this.setXY(el, [x, false]);
1860 setY : function(el, y) {
1861 this.setXY(el, [false, y]);
1865 * Portions of this file are based on pieces of Yahoo User Interface Library
1866 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1867 * YUI licensed under the BSD License:
1868 * http://developer.yahoo.net/yui/license.txt
1869 * <script type="text/javascript">
1873 Roo.lib.Event = function() {
1874 var loadComplete = false;
1876 var unloadListeners = [];
1878 var onAvailStack = [];
1880 var lastError = null;
1893 startInterval: function() {
1894 if (!this._interval) {
1896 var callback = function() {
1897 self._tryPreloadAttach();
1899 this._interval = setInterval(callback, this.POLL_INTERVAL);
1904 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1905 onAvailStack.push({ id: p_id,
1908 override: p_override,
1909 checkReady: false });
1911 retryCount = this.POLL_RETRYS;
1912 this.startInterval();
1916 addListener: function(el, eventName, fn) {
1917 el = Roo.getDom(el);
1922 if ("unload" == eventName) {
1923 unloadListeners[unloadListeners.length] =
1924 [el, eventName, fn];
1928 var wrappedFn = function(e) {
1929 return fn(Roo.lib.Event.getEvent(e));
1932 var li = [el, eventName, fn, wrappedFn];
1934 var index = listeners.length;
1935 listeners[index] = li;
1937 this.doAdd(el, eventName, wrappedFn, false);
1943 removeListener: function(el, eventName, fn) {
1946 el = Roo.getDom(el);
1949 return this.purgeElement(el, false, eventName);
1953 if ("unload" == eventName) {
1955 for (i = 0,len = unloadListeners.length; i < len; i++) {
1956 var li = unloadListeners[i];
1959 li[1] == eventName &&
1961 unloadListeners.splice(i, 1);
1969 var cacheItem = null;
1972 var index = arguments[3];
1974 if ("undefined" == typeof index) {
1975 index = this._getCacheIndex(el, eventName, fn);
1979 cacheItem = listeners[index];
1982 if (!el || !cacheItem) {
1986 this.doRemove(el, eventName, cacheItem[this.WFN], false);
1988 delete listeners[index][this.WFN];
1989 delete listeners[index][this.FN];
1990 listeners.splice(index, 1);
1997 getTarget: function(ev, resolveTextNode) {
1998 ev = ev.browserEvent || ev;
1999 var t = ev.target || ev.srcElement;
2000 return this.resolveTextNode(t);
2004 resolveTextNode: function(node) {
2005 if (Roo.isSafari && node && 3 == node.nodeType) {
2006 return node.parentNode;
2013 getPageX: function(ev) {
2014 ev = ev.browserEvent || ev;
2016 if (!x && 0 !== x) {
2017 x = ev.clientX || 0;
2020 x += this.getScroll()[1];
2028 getPageY: function(ev) {
2029 ev = ev.browserEvent || ev;
2031 if (!y && 0 !== y) {
2032 y = ev.clientY || 0;
2035 y += this.getScroll()[0];
2044 getXY: function(ev) {
2045 ev = ev.browserEvent || ev;
2046 return [this.getPageX(ev), this.getPageY(ev)];
2050 getRelatedTarget: function(ev) {
2051 ev = ev.browserEvent || ev;
2052 var t = ev.relatedTarget;
2054 if (ev.type == "mouseout") {
2056 } else if (ev.type == "mouseover") {
2061 return this.resolveTextNode(t);
2065 getTime: function(ev) {
2066 ev = ev.browserEvent || ev;
2068 var t = new Date().getTime();
2072 this.lastError = ex;
2081 stopEvent: function(ev) {
2082 this.stopPropagation(ev);
2083 this.preventDefault(ev);
2087 stopPropagation: function(ev) {
2088 ev = ev.browserEvent || ev;
2089 if (ev.stopPropagation) {
2090 ev.stopPropagation();
2092 ev.cancelBubble = true;
2097 preventDefault: function(ev) {
2098 ev = ev.browserEvent || ev;
2099 if(ev.preventDefault) {
2100 ev.preventDefault();
2102 ev.returnValue = false;
2107 getEvent: function(e) {
2108 var ev = e || window.event;
2110 var c = this.getEvent.caller;
2112 ev = c.arguments[0];
2113 if (ev && Event == ev.constructor) {
2123 getCharCode: function(ev) {
2124 ev = ev.browserEvent || ev;
2125 return ev.charCode || ev.keyCode || 0;
2129 _getCacheIndex: function(el, eventName, fn) {
2130 for (var i = 0,len = listeners.length; i < len; ++i) {
2131 var li = listeners[i];
2133 li[this.FN] == fn &&
2134 li[this.EL] == el &&
2135 li[this.TYPE] == eventName) {
2147 getEl: function(id) {
2148 return document.getElementById(id);
2152 clearCache: function() {
2156 _load: function(e) {
2157 loadComplete = true;
2158 var EU = Roo.lib.Event;
2162 EU.doRemove(window, "load", EU._load);
2167 _tryPreloadAttach: function() {
2176 var tryAgain = !loadComplete;
2178 tryAgain = (retryCount > 0);
2183 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2184 var item = onAvailStack[i];
2186 var el = this.getEl(item.id);
2189 if (!item.checkReady ||
2192 (document && document.body)) {
2195 if (item.override) {
2196 if (item.override === true) {
2199 scope = item.override;
2202 item.fn.call(scope, item.obj);
2203 onAvailStack[i] = null;
2206 notAvail.push(item);
2211 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2215 this.startInterval();
2217 clearInterval(this._interval);
2218 this._interval = null;
2221 this.locked = false;
2228 purgeElement: function(el, recurse, eventName) {
2229 var elListeners = this.getListeners(el, eventName);
2231 for (var i = 0,len = elListeners.length; i < len; ++i) {
2232 var l = elListeners[i];
2233 this.removeListener(el, l.type, l.fn);
2237 if (recurse && el && el.childNodes) {
2238 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2239 this.purgeElement(el.childNodes[i], recurse, eventName);
2245 getListeners: function(el, eventName) {
2246 var results = [], searchLists;
2248 searchLists = [listeners, unloadListeners];
2249 } else if (eventName == "unload") {
2250 searchLists = [unloadListeners];
2252 searchLists = [listeners];
2255 for (var j = 0; j < searchLists.length; ++j) {
2256 var searchList = searchLists[j];
2257 if (searchList && searchList.length > 0) {
2258 for (var i = 0,len = searchList.length; i < len; ++i) {
2259 var l = searchList[i];
2260 if (l && l[this.EL] === el &&
2261 (!eventName || eventName === l[this.TYPE])) {
2266 adjust: l[this.ADJ_SCOPE],
2274 return (results.length) ? results : null;
2278 _unload: function(e) {
2280 var EU = Roo.lib.Event, i, j, l, len, index;
2282 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2283 l = unloadListeners[i];
2286 if (l[EU.ADJ_SCOPE]) {
2287 if (l[EU.ADJ_SCOPE] === true) {
2290 scope = l[EU.ADJ_SCOPE];
2293 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2294 unloadListeners[i] = null;
2300 unloadListeners = null;
2302 if (listeners && listeners.length > 0) {
2303 j = listeners.length;
2306 l = listeners[index];
2308 EU.removeListener(l[EU.EL], l[EU.TYPE],
2318 EU.doRemove(window, "unload", EU._unload);
2323 getScroll: function() {
2324 var dd = document.documentElement, db = document.body;
2325 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2326 return [dd.scrollTop, dd.scrollLeft];
2328 return [db.scrollTop, db.scrollLeft];
2335 doAdd: function () {
2336 if (window.addEventListener) {
2337 return function(el, eventName, fn, capture) {
2338 el.addEventListener(eventName, fn, (capture));
2340 } else if (window.attachEvent) {
2341 return function(el, eventName, fn, capture) {
2342 el.attachEvent("on" + eventName, fn);
2351 doRemove: function() {
2352 if (window.removeEventListener) {
2353 return function (el, eventName, fn, capture) {
2354 el.removeEventListener(eventName, fn, (capture));
2356 } else if (window.detachEvent) {
2357 return function (el, eventName, fn) {
2358 el.detachEvent("on" + eventName, fn);
2370 var E = Roo.lib.Event;
2371 E.on = E.addListener;
2372 E.un = E.removeListener;
2374 if (document && document.body) {
2377 E.doAdd(window, "load", E._load);
2379 E.doAdd(window, "unload", E._unload);
2380 E._tryPreloadAttach();
2384 * Portions of this file are based on pieces of Yahoo User Interface Library
2385 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2386 * YUI licensed under the BSD License:
2387 * http://developer.yahoo.net/yui/license.txt
2388 * <script type="text/javascript">
2395 request : function(method, uri, cb, data, options) {
2397 var hs = options.headers;
2400 if(hs.hasOwnProperty(h)){
2401 this.initHeader(h, hs[h], false);
2405 if(options.xmlData){
2406 this.initHeader('Content-Type', 'text/xml', false);
2408 data = options.xmlData;
2412 return this.asyncRequest(method, uri, cb, data);
2415 serializeForm : function(form) {
2416 if(typeof form == 'string') {
2417 form = (document.getElementById(form) || document.forms[form]);
2420 var el, name, val, disabled, data = '', hasSubmit = false;
2421 for (var i = 0; i < form.elements.length; i++) {
2422 el = form.elements[i];
2423 disabled = form.elements[i].disabled;
2424 name = form.elements[i].name;
2425 val = form.elements[i].value;
2427 if (!disabled && name){
2431 case 'select-multiple':
2432 for (var j = 0; j < el.options.length; j++) {
2433 if (el.options[j].selected) {
2435 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2438 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2446 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2459 if(hasSubmit == false) {
2460 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2465 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2470 data = data.substr(0, data.length - 1);
2478 useDefaultHeader:true,
2480 defaultPostHeader:'application/x-www-form-urlencoded',
2482 useDefaultXhrHeader:true,
2484 defaultXhrHeader:'XMLHttpRequest',
2486 hasDefaultHeaders:true,
2498 setProgId:function(id)
2500 this.activeX.unshift(id);
2503 setDefaultPostHeader:function(b)
2505 this.useDefaultHeader = b;
2508 setDefaultXhrHeader:function(b)
2510 this.useDefaultXhrHeader = b;
2513 setPollingInterval:function(i)
2515 if (typeof i == 'number' && isFinite(i)) {
2516 this.pollInterval = i;
2520 createXhrObject:function(transactionId)
2526 http = new XMLHttpRequest();
2528 obj = { conn:http, tId:transactionId };
2532 for (var i = 0; i < this.activeX.length; ++i) {
2536 http = new ActiveXObject(this.activeX[i]);
2538 obj = { conn:http, tId:transactionId };
2551 getConnectionObject:function()
2554 var tId = this.transactionId;
2558 o = this.createXhrObject(tId);
2560 this.transactionId++;
2571 asyncRequest:function(method, uri, callback, postData)
2573 var o = this.getConnectionObject();
2579 o.conn.open(method, uri, true);
2581 if (this.useDefaultXhrHeader) {
2582 if (!this.defaultHeaders['X-Requested-With']) {
2583 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2587 if(postData && this.useDefaultHeader){
2588 this.initHeader('Content-Type', this.defaultPostHeader);
2591 if (this.hasDefaultHeaders || this.hasHeaders) {
2595 this.handleReadyState(o, callback);
2596 o.conn.send(postData || null);
2602 handleReadyState:function(o, callback)
2606 if (callback && callback.timeout) {
2607 this.timeout[o.tId] = window.setTimeout(function() {
2608 oConn.abort(o, callback, true);
2609 }, callback.timeout);
2612 this.poll[o.tId] = window.setInterval(
2614 if (o.conn && o.conn.readyState == 4) {
2615 window.clearInterval(oConn.poll[o.tId]);
2616 delete oConn.poll[o.tId];
2618 if(callback && callback.timeout) {
2619 window.clearTimeout(oConn.timeout[o.tId]);
2620 delete oConn.timeout[o.tId];
2623 oConn.handleTransactionResponse(o, callback);
2626 , this.pollInterval);
2629 handleTransactionResponse:function(o, callback, isAbort)
2633 this.releaseObject(o);
2637 var httpStatus, responseObject;
2641 if (o.conn.status !== undefined && o.conn.status != 0) {
2642 httpStatus = o.conn.status;
2654 if (httpStatus >= 200 && httpStatus < 300) {
2655 responseObject = this.createResponseObject(o, callback.argument);
2656 if (callback.success) {
2657 if (!callback.scope) {
2658 callback.success(responseObject);
2663 callback.success.apply(callback.scope, [responseObject]);
2668 switch (httpStatus) {
2676 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2677 if (callback.failure) {
2678 if (!callback.scope) {
2679 callback.failure(responseObject);
2682 callback.failure.apply(callback.scope, [responseObject]);
2687 responseObject = this.createResponseObject(o, callback.argument);
2688 if (callback.failure) {
2689 if (!callback.scope) {
2690 callback.failure(responseObject);
2693 callback.failure.apply(callback.scope, [responseObject]);
2699 this.releaseObject(o);
2700 responseObject = null;
2703 createResponseObject:function(o, callbackArg)
2710 var headerStr = o.conn.getAllResponseHeaders();
2711 var header = headerStr.split('\n');
2712 for (var i = 0; i < header.length; i++) {
2713 var delimitPos = header[i].indexOf(':');
2714 if (delimitPos != -1) {
2715 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2723 obj.status = o.conn.status;
2724 obj.statusText = o.conn.statusText;
2725 obj.getResponseHeader = headerObj;
2726 obj.getAllResponseHeaders = headerStr;
2727 obj.responseText = o.conn.responseText;
2728 obj.responseXML = o.conn.responseXML;
2730 if (typeof callbackArg !== undefined) {
2731 obj.argument = callbackArg;
2737 createExceptionObject:function(tId, callbackArg, isAbort)
2740 var COMM_ERROR = 'communication failure';
2741 var ABORT_CODE = -1;
2742 var ABORT_ERROR = 'transaction aborted';
2748 obj.status = ABORT_CODE;
2749 obj.statusText = ABORT_ERROR;
2752 obj.status = COMM_CODE;
2753 obj.statusText = COMM_ERROR;
2757 obj.argument = callbackArg;
2763 initHeader:function(label, value, isDefault)
2765 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2767 if (headerObj[label] === undefined) {
2768 headerObj[label] = value;
2773 headerObj[label] = value + "," + headerObj[label];
2777 this.hasDefaultHeaders = true;
2780 this.hasHeaders = true;
2785 setHeader:function(o)
2787 if (this.hasDefaultHeaders) {
2788 for (var prop in this.defaultHeaders) {
2789 if (this.defaultHeaders.hasOwnProperty(prop)) {
2790 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2795 if (this.hasHeaders) {
2796 for (var prop in this.headers) {
2797 if (this.headers.hasOwnProperty(prop)) {
2798 o.conn.setRequestHeader(prop, this.headers[prop]);
2802 this.hasHeaders = false;
2806 resetDefaultHeaders:function() {
2807 delete this.defaultHeaders;
2808 this.defaultHeaders = {};
2809 this.hasDefaultHeaders = false;
2812 abort:function(o, callback, isTimeout)
2814 if(this.isCallInProgress(o)) {
2816 window.clearInterval(this.poll[o.tId]);
2817 delete this.poll[o.tId];
2819 delete this.timeout[o.tId];
2822 this.handleTransactionResponse(o, callback, true);
2832 isCallInProgress:function(o)
2835 return o.conn.readyState != 4 && o.conn.readyState != 0;
2844 releaseObject:function(o)
2853 'MSXML2.XMLHTTP.3.0',
2861 * Portions of this file are based on pieces of Yahoo User Interface Library
2862 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2863 * YUI licensed under the BSD License:
2864 * http://developer.yahoo.net/yui/license.txt
2865 * <script type="text/javascript">
2869 Roo.lib.Region = function(t, r, b, l) {
2879 Roo.lib.Region.prototype = {
2880 contains : function(region) {
2881 return ( region.left >= this.left &&
2882 region.right <= this.right &&
2883 region.top >= this.top &&
2884 region.bottom <= this.bottom );
2888 getArea : function() {
2889 return ( (this.bottom - this.top) * (this.right - this.left) );
2892 intersect : function(region) {
2893 var t = Math.max(this.top, region.top);
2894 var r = Math.min(this.right, region.right);
2895 var b = Math.min(this.bottom, region.bottom);
2896 var l = Math.max(this.left, region.left);
2898 if (b >= t && r >= l) {
2899 return new Roo.lib.Region(t, r, b, l);
2904 union : function(region) {
2905 var t = Math.min(this.top, region.top);
2906 var r = Math.max(this.right, region.right);
2907 var b = Math.max(this.bottom, region.bottom);
2908 var l = Math.min(this.left, region.left);
2910 return new Roo.lib.Region(t, r, b, l);
2913 adjust : function(t, l, b, r) {
2922 Roo.lib.Region.getRegion = function(el) {
2923 var p = Roo.lib.Dom.getXY(el);
2926 var r = p[0] + el.offsetWidth;
2927 var b = p[1] + el.offsetHeight;
2930 return new Roo.lib.Region(t, r, b, l);
2933 * Portions of this file are based on pieces of Yahoo User Interface Library
2934 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2935 * YUI licensed under the BSD License:
2936 * http://developer.yahoo.net/yui/license.txt
2937 * <script type="text/javascript">
2940 //@@dep Roo.lib.Region
2943 Roo.lib.Point = function(x, y) {
2944 if (x instanceof Array) {
2948 this.x = this.right = this.left = this[0] = x;
2949 this.y = this.top = this.bottom = this[1] = y;
2952 Roo.lib.Point.prototype = new Roo.lib.Region();
2954 * Portions of this file are based on pieces of Yahoo User Interface Library
2955 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2956 * YUI licensed under the BSD License:
2957 * http://developer.yahoo.net/yui/license.txt
2958 * <script type="text/javascript">
2965 scroll : function(el, args, duration, easing, cb, scope) {
2966 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2969 motion : function(el, args, duration, easing, cb, scope) {
2970 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2973 color : function(el, args, duration, easing, cb, scope) {
2974 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2977 run : function(el, args, duration, easing, cb, scope, type) {
2978 type = type || Roo.lib.AnimBase;
2979 if (typeof easing == "string") {
2980 easing = Roo.lib.Easing[easing];
2982 var anim = new type(el, args, duration, easing);
2983 anim.animateX(function() {
2984 Roo.callback(cb, scope);
2990 * Portions of this file are based on pieces of Yahoo User Interface Library
2991 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2992 * YUI licensed under the BSD License:
2993 * http://developer.yahoo.net/yui/license.txt
2994 * <script type="text/javascript">
3002 if (!libFlyweight) {
3003 libFlyweight = new Roo.Element.Flyweight();
3005 libFlyweight.dom = el;
3006 return libFlyweight;
3009 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3013 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3015 this.init(el, attributes, duration, method);
3019 Roo.lib.AnimBase.fly = fly;
3023 Roo.lib.AnimBase.prototype = {
3025 toString: function() {
3026 var el = this.getEl();
3027 var id = el.id || el.tagName;
3028 return ("Anim " + id);
3032 noNegatives: /width|height|opacity|padding/i,
3033 offsetAttribute: /^((width|height)|(top|left))$/,
3034 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3035 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3039 doMethod: function(attr, start, end) {
3040 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3044 setAttribute: function(attr, val, unit) {
3045 if (this.patterns.noNegatives.test(attr)) {
3046 val = (val > 0) ? val : 0;
3049 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3053 getAttribute: function(attr) {
3054 var el = this.getEl();
3055 var val = fly(el).getStyle(attr);
3057 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3058 return parseFloat(val);
3061 var a = this.patterns.offsetAttribute.exec(attr) || [];
3062 var pos = !!( a[3] );
3063 var box = !!( a[2] );
3066 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3067 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3076 getDefaultUnit: function(attr) {
3077 if (this.patterns.defaultUnit.test(attr)) {
3084 animateX : function(callback, scope) {
3085 var f = function() {
3086 this.onComplete.removeListener(f);
3087 if (typeof callback == "function") {
3088 callback.call(scope || this, this);
3091 this.onComplete.addListener(f, this);
3096 setRuntimeAttribute: function(attr) {
3099 var attributes = this.attributes;
3101 this.runtimeAttributes[attr] = {};
3103 var isset = function(prop) {
3104 return (typeof prop !== 'undefined');
3107 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3111 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3114 if (isset(attributes[attr]['to'])) {
3115 end = attributes[attr]['to'];
3116 } else if (isset(attributes[attr]['by'])) {
3117 if (start.constructor == Array) {
3119 for (var i = 0, len = start.length; i < len; ++i) {
3120 end[i] = start[i] + attributes[attr]['by'][i];
3123 end = start + attributes[attr]['by'];
3127 this.runtimeAttributes[attr].start = start;
3128 this.runtimeAttributes[attr].end = end;
3131 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3135 init: function(el, attributes, duration, method) {
3137 var isAnimated = false;
3140 var startTime = null;
3143 var actualFrames = 0;
3146 el = Roo.getDom(el);
3149 this.attributes = attributes || {};
3152 this.duration = duration || 1;
3155 this.method = method || Roo.lib.Easing.easeNone;
3158 this.useSeconds = true;
3161 this.currentFrame = 0;
3164 this.totalFrames = Roo.lib.AnimMgr.fps;
3167 this.getEl = function() {
3172 this.isAnimated = function() {
3177 this.getStartTime = function() {
3181 this.runtimeAttributes = {};
3184 this.animate = function() {
3185 if (this.isAnimated()) {
3189 this.currentFrame = 0;
3191 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3193 Roo.lib.AnimMgr.registerElement(this);
3197 this.stop = function(finish) {
3199 this.currentFrame = this.totalFrames;
3200 this._onTween.fire();
3202 Roo.lib.AnimMgr.stop(this);
3205 var onStart = function() {
3206 this.onStart.fire();
3208 this.runtimeAttributes = {};
3209 for (var attr in this.attributes) {
3210 this.setRuntimeAttribute(attr);
3215 startTime = new Date();
3219 var onTween = function() {
3221 duration: new Date() - this.getStartTime(),
3222 currentFrame: this.currentFrame
3225 data.toString = function() {
3227 'duration: ' + data.duration +
3228 ', currentFrame: ' + data.currentFrame
3232 this.onTween.fire(data);
3234 var runtimeAttributes = this.runtimeAttributes;
3236 for (var attr in runtimeAttributes) {
3237 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3243 var onComplete = function() {
3244 var actual_duration = (new Date() - startTime) / 1000 ;
3247 duration: actual_duration,
3248 frames: actualFrames,
3249 fps: actualFrames / actual_duration
3252 data.toString = function() {
3254 'duration: ' + data.duration +
3255 ', frames: ' + data.frames +
3256 ', fps: ' + data.fps
3262 this.onComplete.fire(data);
3266 this._onStart = new Roo.util.Event(this);
3267 this.onStart = new Roo.util.Event(this);
3268 this.onTween = new Roo.util.Event(this);
3269 this._onTween = new Roo.util.Event(this);
3270 this.onComplete = new Roo.util.Event(this);
3271 this._onComplete = new Roo.util.Event(this);
3272 this._onStart.addListener(onStart);
3273 this._onTween.addListener(onTween);
3274 this._onComplete.addListener(onComplete);
3279 * Portions of this file are based on pieces of Yahoo User Interface Library
3280 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3281 * YUI licensed under the BSD License:
3282 * http://developer.yahoo.net/yui/license.txt
3283 * <script type="text/javascript">
3287 Roo.lib.AnimMgr = new function() {
3304 this.registerElement = function(tween) {
3305 queue[queue.length] = tween;
3307 tween._onStart.fire();
3312 this.unRegister = function(tween, index) {
3313 tween._onComplete.fire();
3314 index = index || getIndex(tween);
3316 queue.splice(index, 1);
3320 if (tweenCount <= 0) {
3326 this.start = function() {
3327 if (thread === null) {
3328 thread = setInterval(this.run, this.delay);
3333 this.stop = function(tween) {
3335 clearInterval(thread);
3337 for (var i = 0, len = queue.length; i < len; ++i) {
3338 if (queue[0].isAnimated()) {
3339 this.unRegister(queue[0], 0);
3348 this.unRegister(tween);
3353 this.run = function() {
3354 for (var i = 0, len = queue.length; i < len; ++i) {
3355 var tween = queue[i];
3356 if (!tween || !tween.isAnimated()) {
3360 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3362 tween.currentFrame += 1;
3364 if (tween.useSeconds) {
3365 correctFrame(tween);
3367 tween._onTween.fire();
3370 Roo.lib.AnimMgr.stop(tween, i);
3375 var getIndex = function(anim) {
3376 for (var i = 0, len = queue.length; i < len; ++i) {
3377 if (queue[i] == anim) {
3385 var correctFrame = function(tween) {
3386 var frames = tween.totalFrames;
3387 var frame = tween.currentFrame;
3388 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3389 var elapsed = (new Date() - tween.getStartTime());
3392 if (elapsed < tween.duration * 1000) {
3393 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3395 tweak = frames - (frame + 1);
3397 if (tweak > 0 && isFinite(tweak)) {
3398 if (tween.currentFrame + tweak >= frames) {
3399 tweak = frames - (frame + 1);
3402 tween.currentFrame += tweak;
3406 * Portions of this file are based on pieces of Yahoo User Interface Library
3407 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3408 * YUI licensed under the BSD License:
3409 * http://developer.yahoo.net/yui/license.txt
3410 * <script type="text/javascript">
3413 Roo.lib.Bezier = new function() {
3415 this.getPosition = function(points, t) {
3416 var n = points.length;
3419 for (var i = 0; i < n; ++i) {
3420 tmp[i] = [points[i][0], points[i][1]];
3423 for (var j = 1; j < n; ++j) {
3424 for (i = 0; i < n - j; ++i) {
3425 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3426 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3430 return [ tmp[0][0], tmp[0][1] ];
3434 * Portions of this file are based on pieces of Yahoo User Interface Library
3435 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3436 * YUI licensed under the BSD License:
3437 * http://developer.yahoo.net/yui/license.txt
3438 * <script type="text/javascript">
3443 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3444 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3447 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3449 var fly = Roo.lib.AnimBase.fly;
3451 var superclass = Y.ColorAnim.superclass;
3452 var proto = Y.ColorAnim.prototype;
3454 proto.toString = function() {
3455 var el = this.getEl();
3456 var id = el.id || el.tagName;
3457 return ("ColorAnim " + id);
3460 proto.patterns.color = /color$/i;
3461 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3462 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3463 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3464 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3467 proto.parseColor = function(s) {
3468 if (s.length == 3) {
3472 var c = this.patterns.hex.exec(s);
3473 if (c && c.length == 4) {
3474 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3477 c = this.patterns.rgb.exec(s);
3478 if (c && c.length == 4) {
3479 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3482 c = this.patterns.hex3.exec(s);
3483 if (c && c.length == 4) {
3484 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3489 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3490 proto.getAttribute = function(attr) {
3491 var el = this.getEl();
3492 if (this.patterns.color.test(attr)) {
3493 var val = fly(el).getStyle(attr);
3495 if (this.patterns.transparent.test(val)) {
3496 var parent = el.parentNode;
3497 val = fly(parent).getStyle(attr);
3499 while (parent && this.patterns.transparent.test(val)) {
3500 parent = parent.parentNode;
3501 val = fly(parent).getStyle(attr);
3502 if (parent.tagName.toUpperCase() == 'HTML') {
3508 val = superclass.getAttribute.call(this, attr);
3513 proto.getAttribute = function(attr) {
3514 var el = this.getEl();
3515 if (this.patterns.color.test(attr)) {
3516 var val = fly(el).getStyle(attr);
3518 if (this.patterns.transparent.test(val)) {
3519 var parent = el.parentNode;
3520 val = fly(parent).getStyle(attr);
3522 while (parent && this.patterns.transparent.test(val)) {
3523 parent = parent.parentNode;
3524 val = fly(parent).getStyle(attr);
3525 if (parent.tagName.toUpperCase() == 'HTML') {
3531 val = superclass.getAttribute.call(this, attr);
3537 proto.doMethod = function(attr, start, end) {
3540 if (this.patterns.color.test(attr)) {
3542 for (var i = 0, len = start.length; i < len; ++i) {
3543 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3546 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3549 val = superclass.doMethod.call(this, attr, start, end);
3555 proto.setRuntimeAttribute = function(attr) {
3556 superclass.setRuntimeAttribute.call(this, attr);
3558 if (this.patterns.color.test(attr)) {
3559 var attributes = this.attributes;
3560 var start = this.parseColor(this.runtimeAttributes[attr].start);
3561 var end = this.parseColor(this.runtimeAttributes[attr].end);
3563 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3564 end = this.parseColor(attributes[attr].by);
3566 for (var i = 0, len = start.length; i < len; ++i) {
3567 end[i] = start[i] + end[i];
3571 this.runtimeAttributes[attr].start = start;
3572 this.runtimeAttributes[attr].end = end;
3578 * Portions of this file are based on pieces of Yahoo User Interface Library
3579 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3580 * YUI licensed under the BSD License:
3581 * http://developer.yahoo.net/yui/license.txt
3582 * <script type="text/javascript">
3588 easeNone: function (t, b, c, d) {
3589 return c * t / d + b;
3593 easeIn: function (t, b, c, d) {
3594 return c * (t /= d) * t + b;
3598 easeOut: function (t, b, c, d) {
3599 return -c * (t /= d) * (t - 2) + b;
3603 easeBoth: function (t, b, c, d) {
3604 if ((t /= d / 2) < 1) {
3605 return c / 2 * t * t + b;
3608 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3612 easeInStrong: function (t, b, c, d) {
3613 return c * (t /= d) * t * t * t + b;
3617 easeOutStrong: function (t, b, c, d) {
3618 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3622 easeBothStrong: function (t, b, c, d) {
3623 if ((t /= d / 2) < 1) {
3624 return c / 2 * t * t * t * t + b;
3627 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3632 elasticIn: function (t, b, c, d, a, p) {
3636 if ((t /= d) == 1) {
3643 if (!a || a < Math.abs(c)) {
3648 var s = p / (2 * Math.PI) * Math.asin(c / a);
3651 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3655 elasticOut: function (t, b, c, d, a, p) {
3659 if ((t /= d) == 1) {
3666 if (!a || a < Math.abs(c)) {
3671 var s = p / (2 * Math.PI) * Math.asin(c / a);
3674 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3678 elasticBoth: function (t, b, c, d, a, p) {
3683 if ((t /= d / 2) == 2) {
3691 if (!a || a < Math.abs(c)) {
3696 var s = p / (2 * Math.PI) * Math.asin(c / a);
3700 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3701 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3703 return a * Math.pow(2, -10 * (t -= 1)) *
3704 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3709 backIn: function (t, b, c, d, s) {
3710 if (typeof s == 'undefined') {
3713 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3717 backOut: function (t, b, c, d, s) {
3718 if (typeof s == 'undefined') {
3721 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3725 backBoth: function (t, b, c, d, s) {
3726 if (typeof s == 'undefined') {
3730 if ((t /= d / 2 ) < 1) {
3731 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3733 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3737 bounceIn: function (t, b, c, d) {
3738 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3742 bounceOut: function (t, b, c, d) {
3743 if ((t /= d) < (1 / 2.75)) {
3744 return c * (7.5625 * t * t) + b;
3745 } else if (t < (2 / 2.75)) {
3746 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3747 } else if (t < (2.5 / 2.75)) {
3748 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3750 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3754 bounceBoth: function (t, b, c, d) {
3756 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3758 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3761 * Portions of this file are based on pieces of Yahoo User Interface Library
3762 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3763 * YUI licensed under the BSD License:
3764 * http://developer.yahoo.net/yui/license.txt
3765 * <script type="text/javascript">
3769 Roo.lib.Motion = function(el, attributes, duration, method) {
3771 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3775 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3779 var superclass = Y.Motion.superclass;
3780 var proto = Y.Motion.prototype;
3782 proto.toString = function() {
3783 var el = this.getEl();
3784 var id = el.id || el.tagName;
3785 return ("Motion " + id);
3788 proto.patterns.points = /^points$/i;
3790 proto.setAttribute = function(attr, val, unit) {
3791 if (this.patterns.points.test(attr)) {
3792 unit = unit || 'px';
3793 superclass.setAttribute.call(this, 'left', val[0], unit);
3794 superclass.setAttribute.call(this, 'top', val[1], unit);
3796 superclass.setAttribute.call(this, attr, val, unit);
3800 proto.getAttribute = function(attr) {
3801 if (this.patterns.points.test(attr)) {
3803 superclass.getAttribute.call(this, 'left'),
3804 superclass.getAttribute.call(this, 'top')
3807 val = superclass.getAttribute.call(this, attr);
3813 proto.doMethod = function(attr, start, end) {
3816 if (this.patterns.points.test(attr)) {
3817 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3818 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3820 val = superclass.doMethod.call(this, attr, start, end);
3825 proto.setRuntimeAttribute = function(attr) {
3826 if (this.patterns.points.test(attr)) {
3827 var el = this.getEl();
3828 var attributes = this.attributes;
3830 var control = attributes['points']['control'] || [];
3834 if (control.length > 0 && !(control[0] instanceof Array)) {
3835 control = [control];
3838 for (i = 0,len = control.length; i < len; ++i) {
3839 tmp[i] = control[i];
3844 Roo.fly(el).position();
3846 if (isset(attributes['points']['from'])) {
3847 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3850 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3853 start = this.getAttribute('points');
3856 if (isset(attributes['points']['to'])) {
3857 end = translateValues.call(this, attributes['points']['to'], start);
3859 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3860 for (i = 0,len = control.length; i < len; ++i) {
3861 control[i] = translateValues.call(this, control[i], start);
3865 } else if (isset(attributes['points']['by'])) {
3866 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3868 for (i = 0,len = control.length; i < len; ++i) {
3869 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3873 this.runtimeAttributes[attr] = [start];
3875 if (control.length > 0) {
3876 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3879 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3882 superclass.setRuntimeAttribute.call(this, attr);
3886 var translateValues = function(val, start) {
3887 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3888 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3893 var isset = function(prop) {
3894 return (typeof prop !== 'undefined');
3898 * Portions of this file are based on pieces of Yahoo User Interface Library
3899 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3900 * YUI licensed under the BSD License:
3901 * http://developer.yahoo.net/yui/license.txt
3902 * <script type="text/javascript">
3906 Roo.lib.Scroll = function(el, attributes, duration, method) {
3908 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3912 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3916 var superclass = Y.Scroll.superclass;
3917 var proto = Y.Scroll.prototype;
3919 proto.toString = function() {
3920 var el = this.getEl();
3921 var id = el.id || el.tagName;
3922 return ("Scroll " + id);
3925 proto.doMethod = function(attr, start, end) {
3928 if (attr == 'scroll') {
3930 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3931 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3935 val = superclass.doMethod.call(this, attr, start, end);
3940 proto.getAttribute = function(attr) {
3942 var el = this.getEl();
3944 if (attr == 'scroll') {
3945 val = [ el.scrollLeft, el.scrollTop ];
3947 val = superclass.getAttribute.call(this, attr);
3953 proto.setAttribute = function(attr, val, unit) {
3954 var el = this.getEl();
3956 if (attr == 'scroll') {
3957 el.scrollLeft = val[0];
3958 el.scrollTop = val[1];
3960 superclass.setAttribute.call(this, attr, val, unit);
3966 * Ext JS Library 1.1.1
3967 * Copyright(c) 2006-2007, Ext JS, LLC.
3969 * Originally Released Under LGPL - original licence link has changed is not relivant.
3972 * <script type="text/javascript">
3977 * @class Roo.DomHelper
3978 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3979 * 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>.
3982 Roo.DomHelper = function(){
3983 var tempTableEl = null;
3984 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3985 var tableRe = /^table|tbody|tr|td$/i;
3987 // build as innerHTML where available
3989 var createHtml = function(o){
3990 if(typeof o == 'string'){
3999 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4000 if(attr == "style"){
4002 if(typeof s == "function"){
4005 if(typeof s == "string"){
4006 b += ' style="' + s + '"';
4007 }else if(typeof s == "object"){
4010 if(typeof s[key] != "function"){
4011 b += key + ":" + s[key] + ";";
4018 b += ' class="' + o["cls"] + '"';
4019 }else if(attr == "htmlFor"){
4020 b += ' for="' + o["htmlFor"] + '"';
4022 b += " " + attr + '="' + o[attr] + '"';
4026 if(emptyTags.test(o.tag)){
4030 var cn = o.children || o.cn;
4032 //http://bugs.kde.org/show_bug.cgi?id=71506
4033 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4034 for(var i = 0, len = cn.length; i < len; i++) {
4035 b += createHtml(cn[i], b);
4038 b += createHtml(cn, b);
4044 b += "</" + o.tag + ">";
4051 var createDom = function(o, parentNode){
4053 // defininition craeted..
4055 if (o.ns && o.ns != 'html') {
4057 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4058 xmlns[o.ns] = o.xmlns;
4061 if (typeof(xmlns[o.ns]) == 'undefined') {
4062 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4068 if (typeof(o) == 'string') {
4069 return parentNode.appendChild(document.createTextNode(o));
4071 o.tag = o.tag || div;
4072 if (o.ns && Roo.isIE) {
4074 o.tag = o.ns + ':' + o.tag;
4077 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4078 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4081 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4082 attr == "style" || typeof o[attr] == "function") continue;
4084 if(attr=="cls" && Roo.isIE){
4085 el.className = o["cls"];
4087 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4088 else el[attr] = o[attr];
4091 Roo.DomHelper.applyStyles(el, o.style);
4092 var cn = o.children || o.cn;
4094 //http://bugs.kde.org/show_bug.cgi?id=71506
4095 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4096 for(var i = 0, len = cn.length; i < len; i++) {
4097 createDom(cn[i], el);
4104 el.innerHTML = o.html;
4107 parentNode.appendChild(el);
4112 var ieTable = function(depth, s, h, e){
4113 tempTableEl.innerHTML = [s, h, e].join('');
4114 var i = -1, el = tempTableEl;
4121 // kill repeat to save bytes
4125 tbe = '</tbody>'+te,
4131 * Nasty code for IE's broken table implementation
4133 var insertIntoTable = function(tag, where, el, html){
4135 tempTableEl = document.createElement('div');
4140 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4143 if(where == 'beforebegin'){
4147 before = el.nextSibling;
4150 node = ieTable(4, trs, html, tre);
4152 else if(tag == 'tr'){
4153 if(where == 'beforebegin'){
4156 node = ieTable(3, tbs, html, tbe);
4157 } else if(where == 'afterend'){
4158 before = el.nextSibling;
4160 node = ieTable(3, tbs, html, tbe);
4161 } else{ // INTO a TR
4162 if(where == 'afterbegin'){
4163 before = el.firstChild;
4165 node = ieTable(4, trs, html, tre);
4167 } else if(tag == 'tbody'){
4168 if(where == 'beforebegin'){
4171 node = ieTable(2, ts, html, te);
4172 } else if(where == 'afterend'){
4173 before = el.nextSibling;
4175 node = ieTable(2, ts, html, te);
4177 if(where == 'afterbegin'){
4178 before = el.firstChild;
4180 node = ieTable(3, tbs, html, tbe);
4183 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4186 if(where == 'afterbegin'){
4187 before = el.firstChild;
4189 node = ieTable(2, ts, html, te);
4191 el.insertBefore(node, before);
4196 /** True to force the use of DOM instead of html fragments @type Boolean */
4200 * Returns the markup for the passed Element(s) config
4201 * @param {Object} o The Dom object spec (and children)
4204 markup : function(o){
4205 return createHtml(o);
4209 * Applies a style specification to an element
4210 * @param {String/HTMLElement} el The element to apply styles to
4211 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4212 * a function which returns such a specification.
4214 applyStyles : function(el, styles){
4217 if(typeof styles == "string"){
4218 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4220 while ((matches = re.exec(styles)) != null){
4221 el.setStyle(matches[1], matches[2]);
4223 }else if (typeof styles == "object"){
4224 for (var style in styles){
4225 el.setStyle(style, styles[style]);
4227 }else if (typeof styles == "function"){
4228 Roo.DomHelper.applyStyles(el, styles.call());
4234 * Inserts an HTML fragment into the Dom
4235 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4236 * @param {HTMLElement} el The context element
4237 * @param {String} html The HTML fragmenet
4238 * @return {HTMLElement} The new node
4240 insertHtml : function(where, el, html){
4241 where = where.toLowerCase();
4242 if(el.insertAdjacentHTML){
4243 if(tableRe.test(el.tagName)){
4245 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4251 el.insertAdjacentHTML('BeforeBegin', html);
4252 return el.previousSibling;
4254 el.insertAdjacentHTML('AfterBegin', html);
4255 return el.firstChild;
4257 el.insertAdjacentHTML('BeforeEnd', html);
4258 return el.lastChild;
4260 el.insertAdjacentHTML('AfterEnd', html);
4261 return el.nextSibling;
4263 throw 'Illegal insertion point -> "' + where + '"';
4265 var range = el.ownerDocument.createRange();
4269 range.setStartBefore(el);
4270 frag = range.createContextualFragment(html);
4271 el.parentNode.insertBefore(frag, el);
4272 return el.previousSibling;
4275 range.setStartBefore(el.firstChild);
4276 frag = range.createContextualFragment(html);
4277 el.insertBefore(frag, el.firstChild);
4278 return el.firstChild;
4280 el.innerHTML = html;
4281 return el.firstChild;
4285 range.setStartAfter(el.lastChild);
4286 frag = range.createContextualFragment(html);
4287 el.appendChild(frag);
4288 return el.lastChild;
4290 el.innerHTML = html;
4291 return el.lastChild;
4294 range.setStartAfter(el);
4295 frag = range.createContextualFragment(html);
4296 el.parentNode.insertBefore(frag, el.nextSibling);
4297 return el.nextSibling;
4299 throw 'Illegal insertion point -> "' + where + '"';
4303 * Creates new Dom element(s) and inserts them before el
4304 * @param {String/HTMLElement/Element} el The context element
4305 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4306 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4307 * @return {HTMLElement/Roo.Element} The new node
4309 insertBefore : function(el, o, returnElement){
4310 return this.doInsert(el, o, returnElement, "beforeBegin");
4314 * Creates new Dom element(s) and inserts them after el
4315 * @param {String/HTMLElement/Element} el The context element
4316 * @param {Object} o The Dom object spec (and children)
4317 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4318 * @return {HTMLElement/Roo.Element} The new node
4320 insertAfter : function(el, o, returnElement){
4321 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4325 * Creates new Dom element(s) and inserts them as the first child of el
4326 * @param {String/HTMLElement/Element} el The context element
4327 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4328 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4329 * @return {HTMLElement/Roo.Element} The new node
4331 insertFirst : function(el, o, returnElement){
4332 return this.doInsert(el, o, returnElement, "afterBegin");
4336 doInsert : function(el, o, returnElement, pos, sibling){
4337 el = Roo.getDom(el);
4339 if(this.useDom || o.ns){
4340 newNode = createDom(o, null);
4341 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4343 var html = createHtml(o);
4344 newNode = this.insertHtml(pos, el, html);
4346 return returnElement ? Roo.get(newNode, true) : newNode;
4350 * Creates new Dom element(s) and appends them to el
4351 * @param {String/HTMLElement/Element} el The context element
4352 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4353 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4354 * @return {HTMLElement/Roo.Element} The new node
4356 append : function(el, o, returnElement){
4357 el = Roo.getDom(el);
4359 if(this.useDom || o.ns){
4360 newNode = createDom(o, null);
4361 el.appendChild(newNode);
4363 var html = createHtml(o);
4364 newNode = this.insertHtml("beforeEnd", el, html);
4366 return returnElement ? Roo.get(newNode, true) : newNode;
4370 * Creates new Dom element(s) and overwrites the contents of el with them
4371 * @param {String/HTMLElement/Element} el The context element
4372 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4373 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4374 * @return {HTMLElement/Roo.Element} The new node
4376 overwrite : function(el, o, returnElement){
4377 el = Roo.getDom(el);
4380 while (el.childNodes.length) {
4381 el.removeChild(el.firstChild);
4385 el.innerHTML = createHtml(o);
4388 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4392 * Creates a new Roo.DomHelper.Template from the Dom object spec
4393 * @param {Object} o The Dom object spec (and children)
4394 * @return {Roo.DomHelper.Template} The new template
4396 createTemplate : function(o){
4397 var html = createHtml(o);
4398 return new Roo.Template(html);
4404 * Ext JS Library 1.1.1
4405 * Copyright(c) 2006-2007, Ext JS, LLC.
4407 * Originally Released Under LGPL - original licence link has changed is not relivant.
4410 * <script type="text/javascript">
4414 * @class Roo.Template
4415 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4416 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4419 var t = new Roo.Template({
4420 html : '<div name="{id}">' +
4421 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4423 myformat: function (value, allValues) {
4424 return 'XX' + value;
4427 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4429 * 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>.
4431 * @param {Object} cfg - Configuration object.
4433 Roo.Template = function(cfg){
4435 if(cfg instanceof Array){
4437 }else if(arguments.length > 1){
4438 cfg = Array.prototype.join.call(arguments, "");
4442 if (typeof(cfg) == 'object') {
4451 Roo.Template.prototype = {
4454 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4458 * Returns an HTML fragment of this template with the specified values applied.
4459 * @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'})
4460 * @return {String} The HTML fragment
4462 applyTemplate : function(values){
4466 return this.compiled(values);
4468 var useF = this.disableFormats !== true;
4469 var fm = Roo.util.Format, tpl = this;
4470 var fn = function(m, name, format, args){
4472 if(format.substr(0, 5) == "this."){
4473 return tpl.call(format.substr(5), values[name], values);
4476 // quoted values are required for strings in compiled templates,
4477 // but for non compiled we need to strip them
4478 // quoted reversed for jsmin
4479 var re = /^\s*['"](.*)["']\s*$/;
4480 args = args.split(',');
4481 for(var i = 0, len = args.length; i < len; i++){
4482 args[i] = args[i].replace(re, "$1");
4484 args = [values[name]].concat(args);
4486 args = [values[name]];
4488 return fm[format].apply(fm, args);
4491 return values[name] !== undefined ? values[name] : "";
4494 return this.html.replace(this.re, fn);
4503 * Sets the HTML used as the template and optionally compiles it.
4504 * @param {String} html
4505 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4506 * @return {Roo.Template} this
4508 set : function(html, compile){
4510 this.compiled = null;
4518 * True to disable format functions (defaults to false)
4521 disableFormats : false,
4524 * The regular expression used to match template variables
4528 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4531 * Compiles the template into an internal function, eliminating the RegEx overhead.
4532 * @return {Roo.Template} this
4534 compile : function(){
4535 var fm = Roo.util.Format;
4536 var useF = this.disableFormats !== true;
4537 var sep = Roo.isGecko ? "+" : ",";
4538 var fn = function(m, name, format, args){
4540 args = args ? ',' + args : "";
4541 if(format.substr(0, 5) != "this."){
4542 format = "fm." + format + '(';
4544 format = 'this.call("'+ format.substr(5) + '", ';
4548 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4550 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4553 // branched to use + in gecko and [].join() in others
4555 body = "this.compiled = function(values){ return '" +
4556 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4559 body = ["this.compiled = function(values){ return ['"];
4560 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4561 body.push("'].join('');};");
4562 body = body.join('');
4572 // private function used to call members
4573 call : function(fnName, value, allValues){
4574 return this[fnName](value, allValues);
4578 * Applies the supplied values to the template and inserts the new node(s) as the first child of 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 insertFirst: function(el, values, returnElement){
4585 return this.doInsert('afterBegin', el, values, returnElement);
4589 * Applies the supplied values to the template and inserts the new node(s) before el.
4590 * @param {String/HTMLElement/Roo.Element} el The context element
4591 * @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'})
4592 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4593 * @return {HTMLElement/Roo.Element} The new node or Element
4595 insertBefore: function(el, values, returnElement){
4596 return this.doInsert('beforeBegin', el, values, returnElement);
4600 * Applies the supplied values to the template and inserts the new node(s) after el.
4601 * @param {String/HTMLElement/Roo.Element} el The context element
4602 * @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'})
4603 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4604 * @return {HTMLElement/Roo.Element} The new node or Element
4606 insertAfter : function(el, values, returnElement){
4607 return this.doInsert('afterEnd', el, values, returnElement);
4611 * Applies the supplied values to the template and appends the new node(s) to el.
4612 * @param {String/HTMLElement/Roo.Element} el The context element
4613 * @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'})
4614 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4615 * @return {HTMLElement/Roo.Element} The new node or Element
4617 append : function(el, values, returnElement){
4618 return this.doInsert('beforeEnd', el, values, returnElement);
4621 doInsert : function(where, el, values, returnEl){
4622 el = Roo.getDom(el);
4623 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4624 return returnEl ? Roo.get(newNode, true) : newNode;
4628 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4629 * @param {String/HTMLElement/Roo.Element} el The context element
4630 * @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'})
4631 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4632 * @return {HTMLElement/Roo.Element} The new node or Element
4634 overwrite : function(el, values, returnElement){
4635 el = Roo.getDom(el);
4636 el.innerHTML = this.applyTemplate(values);
4637 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4641 * Alias for {@link #applyTemplate}
4644 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4647 Roo.DomHelper.Template = Roo.Template;
4650 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4651 * @param {String/HTMLElement} el A DOM element or its id
4652 * @returns {Roo.Template} The created template
4655 Roo.Template.from = function(el){
4656 el = Roo.getDom(el);
4657 return new Roo.Template(el.value || el.innerHTML);
4660 * Ext JS Library 1.1.1
4661 * Copyright(c) 2006-2007, Ext JS, LLC.
4663 * Originally Released Under LGPL - original licence link has changed is not relivant.
4666 * <script type="text/javascript">
4671 * This is code is also distributed under MIT license for use
4672 * with jQuery and prototype JavaScript libraries.
4675 * @class Roo.DomQuery
4676 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).
4678 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>
4681 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.
4683 <h4>Element Selectors:</h4>
4685 <li> <b>*</b> any element</li>
4686 <li> <b>E</b> an element with the tag E</li>
4687 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4688 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4689 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4690 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4692 <h4>Attribute Selectors:</h4>
4693 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4695 <li> <b>E[foo]</b> has an attribute "foo"</li>
4696 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4697 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4698 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4699 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4700 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4701 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4703 <h4>Pseudo Classes:</h4>
4705 <li> <b>E:first-child</b> E is the first child of its parent</li>
4706 <li> <b>E:last-child</b> E is the last child of its parent</li>
4707 <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>
4708 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4709 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4710 <li> <b>E:only-child</b> E is the only child of its parent</li>
4711 <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>
4712 <li> <b>E:first</b> the first E in the resultset</li>
4713 <li> <b>E:last</b> the last E in the resultset</li>
4714 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4715 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4716 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4717 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4718 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4719 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4720 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4721 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4722 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4724 <h4>CSS Value Selectors:</h4>
4726 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4727 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4728 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4729 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4730 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4731 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4735 Roo.DomQuery = function(){
4736 var cache = {}, simpleCache = {}, valueCache = {};
4737 var nonSpace = /\S/;
4738 var trimRe = /^\s+|\s+$/g;
4739 var tplRe = /\{(\d+)\}/g;
4740 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4741 var tagTokenRe = /^(#)?([\w-\*]+)/;
4742 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4744 function child(p, index){
4746 var n = p.firstChild;
4748 if(n.nodeType == 1){
4759 while((n = n.nextSibling) && n.nodeType != 1);
4764 while((n = n.previousSibling) && n.nodeType != 1);
4768 function children(d){
4769 var n = d.firstChild, ni = -1;
4771 var nx = n.nextSibling;
4772 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4782 function byClassName(c, a, v){
4786 var r = [], ri = -1, cn;
4787 for(var i = 0, ci; ci = c[i]; i++){
4788 if((' '+ci.className+' ').indexOf(v) != -1){
4795 function attrValue(n, attr){
4796 if(!n.tagName && typeof n.length != "undefined"){
4805 if(attr == "class" || attr == "className"){
4808 return n.getAttribute(attr) || n[attr];
4812 function getNodes(ns, mode, tagName){
4813 var result = [], ri = -1, cs;
4817 tagName = tagName || "*";
4818 if(typeof ns.getElementsByTagName != "undefined"){
4822 for(var i = 0, ni; ni = ns[i]; i++){
4823 cs = ni.getElementsByTagName(tagName);
4824 for(var j = 0, ci; ci = cs[j]; j++){
4828 }else if(mode == "/" || mode == ">"){
4829 var utag = tagName.toUpperCase();
4830 for(var i = 0, ni, cn; ni = ns[i]; i++){
4831 cn = ni.children || ni.childNodes;
4832 for(var j = 0, cj; cj = cn[j]; j++){
4833 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4838 }else if(mode == "+"){
4839 var utag = tagName.toUpperCase();
4840 for(var i = 0, n; n = ns[i]; i++){
4841 while((n = n.nextSibling) && n.nodeType != 1);
4842 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4846 }else if(mode == "~"){
4847 for(var i = 0, n; n = ns[i]; i++){
4848 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4857 function concat(a, b){
4861 for(var i = 0, l = b.length; i < l; i++){
4867 function byTag(cs, tagName){
4868 if(cs.tagName || cs == document){
4874 var r = [], ri = -1;
4875 tagName = tagName.toLowerCase();
4876 for(var i = 0, ci; ci = cs[i]; i++){
4877 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4884 function byId(cs, attr, id){
4885 if(cs.tagName || cs == document){
4891 var r = [], ri = -1;
4892 for(var i = 0,ci; ci = cs[i]; i++){
4893 if(ci && ci.id == id){
4901 function byAttribute(cs, attr, value, op, custom){
4902 var r = [], ri = -1, st = custom=="{";
4903 var f = Roo.DomQuery.operators[op];
4904 for(var i = 0, ci; ci = cs[i]; i++){
4907 a = Roo.DomQuery.getStyle(ci, attr);
4909 else if(attr == "class" || attr == "className"){
4911 }else if(attr == "for"){
4913 }else if(attr == "href"){
4914 a = ci.getAttribute("href", 2);
4916 a = ci.getAttribute(attr);
4918 if((f && f(a, value)) || (!f && a)){
4925 function byPseudo(cs, name, value){
4926 return Roo.DomQuery.pseudos[name](cs, value);
4929 // This is for IE MSXML which does not support expandos.
4930 // IE runs the same speed using setAttribute, however FF slows way down
4931 // and Safari completely fails so they need to continue to use expandos.
4932 var isIE = window.ActiveXObject ? true : false;
4934 // this eval is stop the compressor from
4935 // renaming the variable to something shorter
4937 /** eval:var:batch */
4942 function nodupIEXml(cs){
4944 cs[0].setAttribute("_nodup", d);
4946 for(var i = 1, len = cs.length; i < len; i++){
4948 if(!c.getAttribute("_nodup") != d){
4949 c.setAttribute("_nodup", d);
4953 for(var i = 0, len = cs.length; i < len; i++){
4954 cs[i].removeAttribute("_nodup");
4963 var len = cs.length, c, i, r = cs, cj, ri = -1;
4964 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4967 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4968 return nodupIEXml(cs);
4972 for(i = 1; c = cs[i]; i++){
4977 for(var j = 0; j < i; j++){
4980 for(j = i+1; cj = cs[j]; j++){
4992 function quickDiffIEXml(c1, c2){
4994 for(var i = 0, len = c1.length; i < len; i++){
4995 c1[i].setAttribute("_qdiff", d);
4998 for(var i = 0, len = c2.length; i < len; i++){
4999 if(c2[i].getAttribute("_qdiff") != d){
5000 r[r.length] = c2[i];
5003 for(var i = 0, len = c1.length; i < len; i++){
5004 c1[i].removeAttribute("_qdiff");
5009 function quickDiff(c1, c2){
5010 var len1 = c1.length;
5014 if(isIE && c1[0].selectSingleNode){
5015 return quickDiffIEXml(c1, c2);
5018 for(var i = 0; i < len1; i++){
5022 for(var i = 0, len = c2.length; i < len; i++){
5023 if(c2[i]._qdiff != d){
5024 r[r.length] = c2[i];
5030 function quickId(ns, mode, root, id){
5032 var d = root.ownerDocument || root;
5033 return d.getElementById(id);
5035 ns = getNodes(ns, mode, "*");
5036 return byId(ns, null, id);
5040 getStyle : function(el, name){
5041 return Roo.fly(el).getStyle(name);
5044 * Compiles a selector/xpath query into a reusable function. The returned function
5045 * takes one parameter "root" (optional), which is the context node from where the query should start.
5046 * @param {String} selector The selector/xpath query
5047 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5048 * @return {Function}
5050 compile : function(path, type){
5051 type = type || "select";
5053 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5054 var q = path, mode, lq;
5055 var tk = Roo.DomQuery.matchers;
5056 var tklen = tk.length;
5059 // accept leading mode switch
5060 var lmode = q.match(modeRe);
5061 if(lmode && lmode[1]){
5062 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5063 q = q.replace(lmode[1], "");
5065 // strip leading slashes
5066 while(path.substr(0, 1)=="/"){
5067 path = path.substr(1);
5070 while(q && lq != q){
5072 var tm = q.match(tagTokenRe);
5073 if(type == "select"){
5076 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5078 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5080 q = q.replace(tm[0], "");
5081 }else if(q.substr(0, 1) != '@'){
5082 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5087 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5089 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5091 q = q.replace(tm[0], "");
5094 while(!(mm = q.match(modeRe))){
5095 var matched = false;
5096 for(var j = 0; j < tklen; j++){
5098 var m = q.match(t.re);
5100 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5103 q = q.replace(m[0], "");
5108 // prevent infinite loop on bad selector
5110 throw 'Error parsing selector, parsing failed at "' + q + '"';
5114 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5115 q = q.replace(mm[1], "");
5118 fn[fn.length] = "return nodup(n);\n}";
5121 * list of variables that need from compression as they are used by eval.
5131 * eval:var:byClassName
5133 * eval:var:byAttribute
5134 * eval:var:attrValue
5142 * Selects a group of elements.
5143 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5144 * @param {Node} root (optional) The start of the query (defaults to document).
5147 select : function(path, root, type){
5148 if(!root || root == document){
5151 if(typeof root == "string"){
5152 root = document.getElementById(root);
5154 var paths = path.split(",");
5156 for(var i = 0, len = paths.length; i < len; i++){
5157 var p = paths[i].replace(trimRe, "");
5159 cache[p] = Roo.DomQuery.compile(p);
5161 throw p + " is not a valid selector";
5164 var result = cache[p](root);
5165 if(result && result != document){
5166 results = results.concat(result);
5169 if(paths.length > 1){
5170 return nodup(results);
5176 * Selects a single element.
5177 * @param {String} selector The selector/xpath query
5178 * @param {Node} root (optional) The start of the query (defaults to document).
5181 selectNode : function(path, root){
5182 return Roo.DomQuery.select(path, root)[0];
5186 * Selects the value of a node, optionally replacing null with the defaultValue.
5187 * @param {String} selector The selector/xpath query
5188 * @param {Node} root (optional) The start of the query (defaults to document).
5189 * @param {String} defaultValue
5191 selectValue : function(path, root, defaultValue){
5192 path = path.replace(trimRe, "");
5193 if(!valueCache[path]){
5194 valueCache[path] = Roo.DomQuery.compile(path, "select");
5196 var n = valueCache[path](root);
5197 n = n[0] ? n[0] : n;
5198 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5199 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5203 * Selects the value of a node, parsing integers and floats.
5204 * @param {String} selector The selector/xpath query
5205 * @param {Node} root (optional) The start of the query (defaults to document).
5206 * @param {Number} defaultValue
5209 selectNumber : function(path, root, defaultValue){
5210 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5211 return parseFloat(v);
5215 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5216 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5217 * @param {String} selector The simple selector to test
5220 is : function(el, ss){
5221 if(typeof el == "string"){
5222 el = document.getElementById(el);
5224 var isArray = (el instanceof Array);
5225 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5226 return isArray ? (result.length == el.length) : (result.length > 0);
5230 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5231 * @param {Array} el An array of elements to filter
5232 * @param {String} selector The simple selector to test
5233 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5234 * the selector instead of the ones that match
5237 filter : function(els, ss, nonMatches){
5238 ss = ss.replace(trimRe, "");
5239 if(!simpleCache[ss]){
5240 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5242 var result = simpleCache[ss](els);
5243 return nonMatches ? quickDiff(result, els) : result;
5247 * Collection of matching regular expressions and code snippets.
5251 select: 'n = byClassName(n, null, " {1} ");'
5253 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5254 select: 'n = byPseudo(n, "{1}", "{2}");'
5256 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5257 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5260 select: 'n = byId(n, null, "{1}");'
5263 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5268 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5269 * 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, > <.
5272 "=" : function(a, v){
5275 "!=" : function(a, v){
5278 "^=" : function(a, v){
5279 return a && a.substr(0, v.length) == v;
5281 "$=" : function(a, v){
5282 return a && a.substr(a.length-v.length) == v;
5284 "*=" : function(a, v){
5285 return a && a.indexOf(v) !== -1;
5287 "%=" : function(a, v){
5288 return (a % v) == 0;
5290 "|=" : function(a, v){
5291 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5293 "~=" : function(a, v){
5294 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5299 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5300 * and the argument (if any) supplied in the selector.
5303 "first-child" : function(c){
5304 var r = [], ri = -1, n;
5305 for(var i = 0, ci; ci = n = c[i]; i++){
5306 while((n = n.previousSibling) && n.nodeType != 1);
5314 "last-child" : function(c){
5315 var r = [], ri = -1, n;
5316 for(var i = 0, ci; ci = n = c[i]; i++){
5317 while((n = n.nextSibling) && n.nodeType != 1);
5325 "nth-child" : function(c, a) {
5326 var r = [], ri = -1;
5327 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5328 var f = (m[1] || 1) - 0, l = m[2] - 0;
5329 for(var i = 0, n; n = c[i]; i++){
5330 var pn = n.parentNode;
5331 if (batch != pn._batch) {
5333 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5334 if(cn.nodeType == 1){
5341 if (l == 0 || n.nodeIndex == l){
5344 } else if ((n.nodeIndex + l) % f == 0){
5352 "only-child" : function(c){
5353 var r = [], ri = -1;;
5354 for(var i = 0, ci; ci = c[i]; i++){
5355 if(!prev(ci) && !next(ci)){
5362 "empty" : function(c){
5363 var r = [], ri = -1;
5364 for(var i = 0, ci; ci = c[i]; i++){
5365 var cns = ci.childNodes, j = 0, cn, empty = true;
5368 if(cn.nodeType == 1 || cn.nodeType == 3){
5380 "contains" : function(c, v){
5381 var r = [], ri = -1;
5382 for(var i = 0, ci; ci = c[i]; i++){
5383 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5390 "nodeValue" : function(c, v){
5391 var r = [], ri = -1;
5392 for(var i = 0, ci; ci = c[i]; i++){
5393 if(ci.firstChild && ci.firstChild.nodeValue == v){
5400 "checked" : function(c){
5401 var r = [], ri = -1;
5402 for(var i = 0, ci; ci = c[i]; i++){
5403 if(ci.checked == true){
5410 "not" : function(c, ss){
5411 return Roo.DomQuery.filter(c, ss, true);
5414 "odd" : function(c){
5415 return this["nth-child"](c, "odd");
5418 "even" : function(c){
5419 return this["nth-child"](c, "even");
5422 "nth" : function(c, a){
5423 return c[a-1] || [];
5426 "first" : function(c){
5430 "last" : function(c){
5431 return c[c.length-1] || [];
5434 "has" : function(c, ss){
5435 var s = Roo.DomQuery.select;
5436 var r = [], ri = -1;
5437 for(var i = 0, ci; ci = c[i]; i++){
5438 if(s(ss, ci).length > 0){
5445 "next" : function(c, ss){
5446 var is = Roo.DomQuery.is;
5447 var r = [], ri = -1;
5448 for(var i = 0, ci; ci = c[i]; i++){
5457 "prev" : function(c, ss){
5458 var is = Roo.DomQuery.is;
5459 var r = [], ri = -1;
5460 for(var i = 0, ci; ci = c[i]; i++){
5473 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5474 * @param {String} path The selector/xpath query
5475 * @param {Node} root (optional) The start of the query (defaults to document).
5480 Roo.query = Roo.DomQuery.select;
5483 * Ext JS Library 1.1.1
5484 * Copyright(c) 2006-2007, Ext JS, LLC.
5486 * Originally Released Under LGPL - original licence link has changed is not relivant.
5489 * <script type="text/javascript">
5493 * @class Roo.util.Observable
5494 * Base class that provides a common interface for publishing events. Subclasses are expected to
5495 * to have a property "events" with all the events defined.<br>
5498 Employee = function(name){
5505 Roo.extend(Employee, Roo.util.Observable);
5507 * @param {Object} config properties to use (incuding events / listeners)
5510 Roo.util.Observable = function(cfg){
5513 this.addEvents(cfg.events || {});
5515 delete cfg.events; // make sure
5518 Roo.apply(this, cfg);
5521 this.on(this.listeners);
5522 delete this.listeners;
5525 Roo.util.Observable.prototype = {
5527 * @cfg {Object} listeners list of events and functions to call for this object,
5531 'click' : function(e) {
5541 * Fires the specified event with the passed parameters (minus the event name).
5542 * @param {String} eventName
5543 * @param {Object...} args Variable number of parameters are passed to handlers
5544 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5546 fireEvent : function(){
5547 var ce = this.events[arguments[0].toLowerCase()];
5548 if(typeof ce == "object"){
5549 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5556 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5559 * Appends an event handler to this component
5560 * @param {String} eventName The type of event to listen for
5561 * @param {Function} handler The method the event invokes
5562 * @param {Object} scope (optional) The scope in which to execute the handler
5563 * function. The handler function's "this" context.
5564 * @param {Object} options (optional) An object containing handler configuration
5565 * properties. This may contain any of the following properties:<ul>
5566 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5567 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5568 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5569 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5570 * by the specified number of milliseconds. If the event fires again within that time, the original
5571 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5574 * <b>Combining Options</b><br>
5575 * Using the options argument, it is possible to combine different types of listeners:<br>
5577 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5579 el.on('click', this.onClick, this, {
5586 * <b>Attaching multiple handlers in 1 call</b><br>
5587 * The method also allows for a single argument to be passed which is a config object containing properties
5588 * which specify multiple handlers.
5597 fn: this.onMouseOver,
5601 fn: this.onMouseOut,
5607 * Or a shorthand syntax which passes the same scope object to all handlers:
5610 'click': this.onClick,
5611 'mouseover': this.onMouseOver,
5612 'mouseout': this.onMouseOut,
5617 addListener : function(eventName, fn, scope, o){
5618 if(typeof eventName == "object"){
5621 if(this.filterOptRe.test(e)){
5624 if(typeof o[e] == "function"){
5626 this.addListener(e, o[e], o.scope, o);
5628 // individual options
5629 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5634 o = (!o || typeof o == "boolean") ? {} : o;
5635 eventName = eventName.toLowerCase();
5636 var ce = this.events[eventName] || true;
5637 if(typeof ce == "boolean"){
5638 ce = new Roo.util.Event(this, eventName);
5639 this.events[eventName] = ce;
5641 ce.addListener(fn, scope, o);
5645 * Removes a listener
5646 * @param {String} eventName The type of event to listen for
5647 * @param {Function} handler The handler to remove
5648 * @param {Object} scope (optional) The scope (this object) for the handler
5650 removeListener : function(eventName, fn, scope){
5651 var ce = this.events[eventName.toLowerCase()];
5652 if(typeof ce == "object"){
5653 ce.removeListener(fn, scope);
5658 * Removes all listeners for this object
5660 purgeListeners : function(){
5661 for(var evt in this.events){
5662 if(typeof this.events[evt] == "object"){
5663 this.events[evt].clearListeners();
5668 relayEvents : function(o, events){
5669 var createHandler = function(ename){
5671 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5674 for(var i = 0, len = events.length; i < len; i++){
5675 var ename = events[i];
5676 if(!this.events[ename]){ this.events[ename] = true; };
5677 o.on(ename, createHandler(ename), this);
5682 * Used to define events on this Observable
5683 * @param {Object} object The object with the events defined
5685 addEvents : function(o){
5689 Roo.applyIf(this.events, o);
5693 * Checks to see if this object has any listeners for a specified event
5694 * @param {String} eventName The name of the event to check for
5695 * @return {Boolean} True if the event is being listened for, else false
5697 hasListener : function(eventName){
5698 var e = this.events[eventName];
5699 return typeof e == "object" && e.listeners.length > 0;
5703 * Appends an event handler to this element (shorthand for addListener)
5704 * @param {String} eventName The type of event to listen for
5705 * @param {Function} handler The method the event invokes
5706 * @param {Object} scope (optional) The scope in which to execute the handler
5707 * function. The handler function's "this" context.
5708 * @param {Object} options (optional)
5711 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5713 * Removes a listener (shorthand for removeListener)
5714 * @param {String} eventName The type of event to listen for
5715 * @param {Function} handler The handler to remove
5716 * @param {Object} scope (optional) The scope (this object) for the handler
5719 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5722 * Starts capture on the specified Observable. All events will be passed
5723 * to the supplied function with the event name + standard signature of the event
5724 * <b>before</b> the event is fired. If the supplied function returns false,
5725 * the event will not fire.
5726 * @param {Observable} o The Observable to capture
5727 * @param {Function} fn The function to call
5728 * @param {Object} scope (optional) The scope (this object) for the fn
5731 Roo.util.Observable.capture = function(o, fn, scope){
5732 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5736 * Removes <b>all</b> added captures from the Observable.
5737 * @param {Observable} o The Observable to release
5740 Roo.util.Observable.releaseCapture = function(o){
5741 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5746 var createBuffered = function(h, o, scope){
5747 var task = new Roo.util.DelayedTask();
5749 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5753 var createSingle = function(h, e, fn, scope){
5755 e.removeListener(fn, scope);
5756 return h.apply(scope, arguments);
5760 var createDelayed = function(h, o, scope){
5762 var args = Array.prototype.slice.call(arguments, 0);
5763 setTimeout(function(){
5764 h.apply(scope, args);
5769 Roo.util.Event = function(obj, name){
5772 this.listeners = [];
5775 Roo.util.Event.prototype = {
5776 addListener : function(fn, scope, options){
5777 var o = options || {};
5778 scope = scope || this.obj;
5779 if(!this.isListening(fn, scope)){
5780 var l = {fn: fn, scope: scope, options: o};
5783 h = createDelayed(h, o, scope);
5786 h = createSingle(h, this, fn, scope);
5789 h = createBuffered(h, o, scope);
5792 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5793 this.listeners.push(l);
5795 this.listeners = this.listeners.slice(0);
5796 this.listeners.push(l);
5801 findListener : function(fn, scope){
5802 scope = scope || this.obj;
5803 var ls = this.listeners;
5804 for(var i = 0, len = ls.length; i < len; i++){
5806 if(l.fn == fn && l.scope == scope){
5813 isListening : function(fn, scope){
5814 return this.findListener(fn, scope) != -1;
5817 removeListener : function(fn, scope){
5819 if((index = this.findListener(fn, scope)) != -1){
5821 this.listeners.splice(index, 1);
5823 this.listeners = this.listeners.slice(0);
5824 this.listeners.splice(index, 1);
5831 clearListeners : function(){
5832 this.listeners = [];
5836 var ls = this.listeners, scope, len = ls.length;
5839 var args = Array.prototype.slice.call(arguments, 0);
5840 for(var i = 0; i < len; i++){
5842 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5843 this.firing = false;
5847 this.firing = false;
5854 * Ext JS Library 1.1.1
5855 * Copyright(c) 2006-2007, Ext JS, LLC.
5857 * Originally Released Under LGPL - original licence link has changed is not relivant.
5860 * <script type="text/javascript">
5864 * @class Roo.EventManager
5865 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5866 * several useful events directly.
5867 * See {@link Roo.EventObject} for more details on normalized event objects.
5870 Roo.EventManager = function(){
5871 var docReadyEvent, docReadyProcId, docReadyState = false;
5872 var resizeEvent, resizeTask, textEvent, textSize;
5873 var E = Roo.lib.Event;
5874 var D = Roo.lib.Dom;
5877 var fireDocReady = function(){
5879 docReadyState = true;
5882 clearInterval(docReadyProcId);
5884 if(Roo.isGecko || Roo.isOpera) {
5885 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5888 var defer = document.getElementById("ie-deferred-loader");
5890 defer.onreadystatechange = null;
5891 defer.parentNode.removeChild(defer);
5895 docReadyEvent.fire();
5896 docReadyEvent.clearListeners();
5901 var initDocReady = function(){
5902 docReadyEvent = new Roo.util.Event();
5903 if(Roo.isGecko || Roo.isOpera) {
5904 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5906 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5907 var defer = document.getElementById("ie-deferred-loader");
5908 defer.onreadystatechange = function(){
5909 if(this.readyState == "complete"){
5913 }else if(Roo.isSafari){
5914 docReadyProcId = setInterval(function(){
5915 var rs = document.readyState;
5916 if(rs == "complete") {
5921 // no matter what, make sure it fires on load
5922 E.on(window, "load", fireDocReady);
5925 var createBuffered = function(h, o){
5926 var task = new Roo.util.DelayedTask(h);
5928 // create new event object impl so new events don't wipe out properties
5929 e = new Roo.EventObjectImpl(e);
5930 task.delay(o.buffer, h, null, [e]);
5934 var createSingle = function(h, el, ename, fn){
5936 Roo.EventManager.removeListener(el, ename, fn);
5941 var createDelayed = function(h, o){
5943 // create new event object impl so new events don't wipe out properties
5944 e = new Roo.EventObjectImpl(e);
5945 setTimeout(function(){
5951 var listen = function(element, ename, opt, fn, scope){
5952 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5953 fn = fn || o.fn; scope = scope || o.scope;
5954 var el = Roo.getDom(element);
5956 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5958 var h = function(e){
5959 e = Roo.EventObject.setEvent(e);
5962 t = e.getTarget(o.delegate, el);
5969 if(o.stopEvent === true){
5972 if(o.preventDefault === true){
5975 if(o.stopPropagation === true){
5976 e.stopPropagation();
5979 if(o.normalized === false){
5983 fn.call(scope || el, e, t, o);
5986 h = createDelayed(h, o);
5989 h = createSingle(h, el, ename, fn);
5992 h = createBuffered(h, o);
5994 fn._handlers = fn._handlers || [];
5995 fn._handlers.push([Roo.id(el), ename, h]);
5998 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5999 el.addEventListener("DOMMouseScroll", h, false);
6000 E.on(window, 'unload', function(){
6001 el.removeEventListener("DOMMouseScroll", h, false);
6004 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6005 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6010 var stopListening = function(el, ename, fn){
6011 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6013 for(var i = 0, len = hds.length; i < len; i++){
6015 if(h[0] == id && h[1] == ename){
6022 E.un(el, ename, hd);
6023 el = Roo.getDom(el);
6024 if(ename == "mousewheel" && el.addEventListener){
6025 el.removeEventListener("DOMMouseScroll", hd, false);
6027 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6028 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6032 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6039 * @scope Roo.EventManager
6044 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6045 * object with a Roo.EventObject
6046 * @param {Function} fn The method the event invokes
6047 * @param {Object} scope An object that becomes the scope of the handler
6048 * @param {boolean} override If true, the obj passed in becomes
6049 * the execution scope of the listener
6050 * @return {Function} The wrapped function
6053 wrap : function(fn, scope, override){
6055 Roo.EventObject.setEvent(e);
6056 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6061 * Appends an event handler to an element (shorthand for addListener)
6062 * @param {String/HTMLElement} element The html element or id to assign the
6063 * @param {String} eventName The type of event to listen for
6064 * @param {Function} handler The method the event invokes
6065 * @param {Object} scope (optional) The scope in which to execute the handler
6066 * function. The handler function's "this" context.
6067 * @param {Object} options (optional) An object containing handler configuration
6068 * properties. This may contain any of the following properties:<ul>
6069 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6070 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6071 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6072 * <li>preventDefault {Boolean} True to prevent the default action</li>
6073 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6074 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6075 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6076 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6077 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6078 * by the specified number of milliseconds. If the event fires again within that time, the original
6079 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6082 * <b>Combining Options</b><br>
6083 * Using the options argument, it is possible to combine different types of listeners:<br>
6085 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6087 el.on('click', this.onClick, this, {
6094 * <b>Attaching multiple handlers in 1 call</b><br>
6095 * The method also allows for a single argument to be passed which is a config object containing properties
6096 * which specify multiple handlers.
6106 fn: this.onMouseOver
6115 * Or a shorthand syntax:<br>
6118 'click' : this.onClick,
6119 'mouseover' : this.onMouseOver,
6120 'mouseout' : this.onMouseOut
6124 addListener : function(element, eventName, fn, scope, options){
6125 if(typeof eventName == "object"){
6131 if(typeof o[e] == "function"){
6133 listen(element, e, o, o[e], o.scope);
6135 // individual options
6136 listen(element, e, o[e]);
6141 return listen(element, eventName, options, fn, scope);
6145 * Removes an event handler
6147 * @param {String/HTMLElement} element The id or html element to remove the
6149 * @param {String} eventName The type of event
6150 * @param {Function} fn
6151 * @return {Boolean} True if a listener was actually removed
6153 removeListener : function(element, eventName, fn){
6154 return stopListening(element, eventName, fn);
6158 * Fires when the document is ready (before onload and before images are loaded). Can be
6159 * accessed shorthanded Roo.onReady().
6160 * @param {Function} fn The method the event invokes
6161 * @param {Object} scope An object that becomes the scope of the handler
6162 * @param {boolean} options
6164 onDocumentReady : function(fn, scope, options){
6165 if(docReadyState){ // if it already fired
6166 docReadyEvent.addListener(fn, scope, options);
6167 docReadyEvent.fire();
6168 docReadyEvent.clearListeners();
6174 docReadyEvent.addListener(fn, scope, options);
6178 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6179 * @param {Function} fn The method the event invokes
6180 * @param {Object} scope An object that becomes the scope of the handler
6181 * @param {boolean} options
6183 onWindowResize : function(fn, scope, options){
6185 resizeEvent = new Roo.util.Event();
6186 resizeTask = new Roo.util.DelayedTask(function(){
6187 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6189 E.on(window, "resize", function(){
6191 resizeTask.delay(50);
6193 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6197 resizeEvent.addListener(fn, scope, options);
6201 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6202 * @param {Function} fn The method the event invokes
6203 * @param {Object} scope An object that becomes the scope of the handler
6204 * @param {boolean} options
6206 onTextResize : function(fn, scope, options){
6208 textEvent = new Roo.util.Event();
6209 var textEl = new Roo.Element(document.createElement('div'));
6210 textEl.dom.className = 'x-text-resize';
6211 textEl.dom.innerHTML = 'X';
6212 textEl.appendTo(document.body);
6213 textSize = textEl.dom.offsetHeight;
6214 setInterval(function(){
6215 if(textEl.dom.offsetHeight != textSize){
6216 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6218 }, this.textResizeInterval);
6220 textEvent.addListener(fn, scope, options);
6224 * Removes the passed window resize listener.
6225 * @param {Function} fn The method the event invokes
6226 * @param {Object} scope The scope of handler
6228 removeResizeListener : function(fn, scope){
6230 resizeEvent.removeListener(fn, scope);
6235 fireResize : function(){
6237 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6241 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6245 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6247 textResizeInterval : 50
6252 * @scopeAlias pub=Roo.EventManager
6256 * Appends an event handler to an element (shorthand for addListener)
6257 * @param {String/HTMLElement} element The html element or id to assign the
6258 * @param {String} eventName The type of event to listen for
6259 * @param {Function} handler The method the event invokes
6260 * @param {Object} scope (optional) The scope in which to execute the handler
6261 * function. The handler function's "this" context.
6262 * @param {Object} options (optional) An object containing handler configuration
6263 * properties. This may contain any of the following properties:<ul>
6264 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6265 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6266 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6267 * <li>preventDefault {Boolean} True to prevent the default action</li>
6268 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6269 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6270 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6271 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6272 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6273 * by the specified number of milliseconds. If the event fires again within that time, the original
6274 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6277 * <b>Combining Options</b><br>
6278 * Using the options argument, it is possible to combine different types of listeners:<br>
6280 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6282 el.on('click', this.onClick, this, {
6289 * <b>Attaching multiple handlers in 1 call</b><br>
6290 * The method also allows for a single argument to be passed which is a config object containing properties
6291 * which specify multiple handlers.
6301 fn: this.onMouseOver
6310 * Or a shorthand syntax:<br>
6313 'click' : this.onClick,
6314 'mouseover' : this.onMouseOver,
6315 'mouseout' : this.onMouseOut
6319 pub.on = pub.addListener;
6320 pub.un = pub.removeListener;
6322 pub.stoppedMouseDownEvent = new Roo.util.Event();
6326 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6327 * @param {Function} fn The method the event invokes
6328 * @param {Object} scope An object that becomes the scope of the handler
6329 * @param {boolean} override If true, the obj passed in becomes
6330 * the execution scope of the listener
6334 Roo.onReady = Roo.EventManager.onDocumentReady;
6336 Roo.onReady(function(){
6337 var bd = Roo.get(document.body);
6342 : Roo.isGecko ? "roo-gecko"
6343 : Roo.isOpera ? "roo-opera"
6344 : Roo.isSafari ? "roo-safari" : ""];
6347 cls.push("roo-mac");
6350 cls.push("roo-linux");
6352 if(Roo.isBorderBox){
6353 cls.push('roo-border-box');
6355 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6356 var p = bd.dom.parentNode;
6358 p.className += ' roo-strict';
6361 bd.addClass(cls.join(' '));
6365 * @class Roo.EventObject
6366 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6367 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6370 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6372 var target = e.getTarget();
6375 var myDiv = Roo.get("myDiv");
6376 myDiv.on("click", handleClick);
6378 Roo.EventManager.on("myDiv", 'click', handleClick);
6379 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6383 Roo.EventObject = function(){
6385 var E = Roo.lib.Event;
6387 // safari keypress events for special keys return bad keycodes
6390 63235 : 39, // right
6393 63276 : 33, // page up
6394 63277 : 34, // page down
6395 63272 : 46, // delete
6400 // normalize button clicks
6401 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6402 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6404 Roo.EventObjectImpl = function(e){
6406 this.setEvent(e.browserEvent || e);
6409 Roo.EventObjectImpl.prototype = {
6411 * Used to fix doc tools.
6412 * @scope Roo.EventObject.prototype
6418 /** The normal browser event */
6419 browserEvent : null,
6420 /** The button pressed in a mouse event */
6422 /** True if the shift key was down during the event */
6424 /** True if the control key was down during the event */
6426 /** True if the alt key was down during the event */
6485 setEvent : function(e){
6486 if(e == this || (e && e.browserEvent)){ // already wrapped
6489 this.browserEvent = e;
6491 // normalize buttons
6492 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6493 if(e.type == 'click' && this.button == -1){
6497 this.shiftKey = e.shiftKey;
6498 // mac metaKey behaves like ctrlKey
6499 this.ctrlKey = e.ctrlKey || e.metaKey;
6500 this.altKey = e.altKey;
6501 // in getKey these will be normalized for the mac
6502 this.keyCode = e.keyCode;
6503 // keyup warnings on firefox.
6504 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6505 // cache the target for the delayed and or buffered events
6506 this.target = E.getTarget(e);
6508 this.xy = E.getXY(e);
6511 this.shiftKey = false;
6512 this.ctrlKey = false;
6513 this.altKey = false;
6523 * Stop the event (preventDefault and stopPropagation)
6525 stopEvent : function(){
6526 if(this.browserEvent){
6527 if(this.browserEvent.type == 'mousedown'){
6528 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6530 E.stopEvent(this.browserEvent);
6535 * Prevents the browsers default handling of the event.
6537 preventDefault : function(){
6538 if(this.browserEvent){
6539 E.preventDefault(this.browserEvent);
6544 isNavKeyPress : function(){
6545 var k = this.keyCode;
6546 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6547 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6550 isSpecialKey : function(){
6551 var k = this.keyCode;
6552 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6553 (k == 16) || (k == 17) ||
6554 (k >= 18 && k <= 20) ||
6555 (k >= 33 && k <= 35) ||
6556 (k >= 36 && k <= 39) ||
6557 (k >= 44 && k <= 45);
6560 * Cancels bubbling of the event.
6562 stopPropagation : function(){
6563 if(this.browserEvent){
6564 if(this.type == 'mousedown'){
6565 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6567 E.stopPropagation(this.browserEvent);
6572 * Gets the key code for the event.
6575 getCharCode : function(){
6576 return this.charCode || this.keyCode;
6580 * Returns a normalized keyCode for the event.
6581 * @return {Number} The key code
6583 getKey : function(){
6584 var k = this.keyCode || this.charCode;
6585 return Roo.isSafari ? (safariKeys[k] || k) : k;
6589 * Gets the x coordinate of the event.
6592 getPageX : function(){
6597 * Gets the y coordinate of the event.
6600 getPageY : function(){
6605 * Gets the time of the event.
6608 getTime : function(){
6609 if(this.browserEvent){
6610 return E.getTime(this.browserEvent);
6616 * Gets the page coordinates of the event.
6617 * @return {Array} The xy values like [x, y]
6624 * Gets the target for the event.
6625 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6626 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6627 search as a number or element (defaults to 10 || document.body)
6628 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6629 * @return {HTMLelement}
6631 getTarget : function(selector, maxDepth, returnEl){
6632 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6635 * Gets the related target.
6636 * @return {HTMLElement}
6638 getRelatedTarget : function(){
6639 if(this.browserEvent){
6640 return E.getRelatedTarget(this.browserEvent);
6646 * Normalizes mouse wheel delta across browsers
6647 * @return {Number} The delta
6649 getWheelDelta : function(){
6650 var e = this.browserEvent;
6652 if(e.wheelDelta){ /* IE/Opera. */
6653 delta = e.wheelDelta/120;
6654 }else if(e.detail){ /* Mozilla case. */
6655 delta = -e.detail/3;
6661 * Returns true if the control, meta, shift or alt key was pressed during this event.
6664 hasModifier : function(){
6665 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6669 * Returns true if the target of this event equals el or is a child of el
6670 * @param {String/HTMLElement/Element} el
6671 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6674 within : function(el, related){
6675 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6676 return t && Roo.fly(el).contains(t);
6679 getPoint : function(){
6680 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6684 return new Roo.EventObjectImpl();
6689 * Ext JS Library 1.1.1
6690 * Copyright(c) 2006-2007, Ext JS, LLC.
6692 * Originally Released Under LGPL - original licence link has changed is not relivant.
6695 * <script type="text/javascript">
6699 // was in Composite Element!??!?!
6702 var D = Roo.lib.Dom;
6703 var E = Roo.lib.Event;
6704 var A = Roo.lib.Anim;
6706 // local style camelizing for speed
6708 var camelRe = /(-[a-z])/gi;
6709 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6710 var view = document.defaultView;
6713 * @class Roo.Element
6714 * Represents an Element in the DOM.<br><br>
6717 var el = Roo.get("my-div");
6720 var el = getEl("my-div");
6722 // or with a DOM element
6723 var el = Roo.get(myDivElement);
6725 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6726 * each call instead of constructing a new one.<br><br>
6727 * <b>Animations</b><br />
6728 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6729 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6731 Option Default Description
6732 --------- -------- ---------------------------------------------
6733 duration .35 The duration of the animation in seconds
6734 easing easeOut The YUI easing method
6735 callback none A function to execute when the anim completes
6736 scope this The scope (this) of the callback function
6738 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6739 * manipulate the animation. Here's an example:
6741 var el = Roo.get("my-div");
6746 // default animation
6747 el.setWidth(100, true);
6749 // animation with some options set
6756 // using the "anim" property to get the Anim object
6762 el.setWidth(100, opt);
6764 if(opt.anim.isAnimated()){
6768 * <b> Composite (Collections of) Elements</b><br />
6769 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6770 * @constructor Create a new Element directly.
6771 * @param {String/HTMLElement} element
6772 * @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).
6774 Roo.Element = function(element, forceNew){
6775 var dom = typeof element == "string" ?
6776 document.getElementById(element) : element;
6777 if(!dom){ // invalid id/element
6781 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6782 return Roo.Element.cache[id];
6792 * The DOM element ID
6795 this.id = id || Roo.id(dom);
6798 var El = Roo.Element;
6802 * The element's default display mode (defaults to "")
6805 originalDisplay : "",
6809 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6814 * Sets the element's visibility mode. When setVisible() is called it
6815 * will use this to determine whether to set the visibility or the display property.
6816 * @param visMode Element.VISIBILITY or Element.DISPLAY
6817 * @return {Roo.Element} this
6819 setVisibilityMode : function(visMode){
6820 this.visibilityMode = visMode;
6824 * Convenience method for setVisibilityMode(Element.DISPLAY)
6825 * @param {String} display (optional) What to set display to when visible
6826 * @return {Roo.Element} this
6828 enableDisplayMode : function(display){
6829 this.setVisibilityMode(El.DISPLAY);
6830 if(typeof display != "undefined") this.originalDisplay = display;
6835 * 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)
6836 * @param {String} selector The simple selector to test
6837 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6838 search as a number or element (defaults to 10 || document.body)
6839 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6840 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6842 findParent : function(simpleSelector, maxDepth, returnEl){
6843 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6844 maxDepth = maxDepth || 50;
6845 if(typeof maxDepth != "number"){
6846 stopEl = Roo.getDom(maxDepth);
6849 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6850 if(dq.is(p, simpleSelector)){
6851 return returnEl ? Roo.get(p) : p;
6861 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6862 * @param {String} selector The simple selector to test
6863 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6864 search as a number or element (defaults to 10 || document.body)
6865 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6866 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6868 findParentNode : function(simpleSelector, maxDepth, returnEl){
6869 var p = Roo.fly(this.dom.parentNode, '_internal');
6870 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6874 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6875 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6876 * @param {String} selector The simple selector to test
6877 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6878 search as a number or element (defaults to 10 || document.body)
6879 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6881 up : function(simpleSelector, maxDepth){
6882 return this.findParentNode(simpleSelector, maxDepth, true);
6888 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6889 * @param {String} selector The simple selector to test
6890 * @return {Boolean} True if this element matches the selector, else false
6892 is : function(simpleSelector){
6893 return Roo.DomQuery.is(this.dom, simpleSelector);
6897 * Perform animation on this element.
6898 * @param {Object} args The YUI animation control args
6899 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6900 * @param {Function} onComplete (optional) Function to call when animation completes
6901 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6902 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6903 * @return {Roo.Element} this
6905 animate : function(args, duration, onComplete, easing, animType){
6906 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6911 * @private Internal animation call
6913 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6914 animType = animType || 'run';
6916 var anim = Roo.lib.Anim[animType](
6918 (opt.duration || defaultDur) || .35,
6919 (opt.easing || defaultEase) || 'easeOut',
6921 Roo.callback(cb, this);
6922 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6930 // private legacy anim prep
6931 preanim : function(a, i){
6932 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6936 * Removes worthless text nodes
6937 * @param {Boolean} forceReclean (optional) By default the element
6938 * keeps track if it has been cleaned already so
6939 * you can call this over and over. However, if you update the element and
6940 * need to force a reclean, you can pass true.
6942 clean : function(forceReclean){
6943 if(this.isCleaned && forceReclean !== true){
6947 var d = this.dom, n = d.firstChild, ni = -1;
6949 var nx = n.nextSibling;
6950 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6957 this.isCleaned = true;
6962 calcOffsetsTo : function(el){
6965 var restorePos = false;
6966 if(el.getStyle('position') == 'static'){
6967 el.position('relative');
6972 while(op && op != d && op.tagName != 'HTML'){
6975 op = op.offsetParent;
6978 el.position('static');
6984 * Scrolls this element into view within the passed container.
6985 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6986 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6987 * @return {Roo.Element} this
6989 scrollIntoView : function(container, hscroll){
6990 var c = Roo.getDom(container) || document.body;
6993 var o = this.calcOffsetsTo(c),
6996 b = t+el.offsetHeight,
6997 r = l+el.offsetWidth;
6999 var ch = c.clientHeight;
7000 var ct = parseInt(c.scrollTop, 10);
7001 var cl = parseInt(c.scrollLeft, 10);
7003 var cr = cl + c.clientWidth;
7011 if(hscroll !== false){
7015 c.scrollLeft = r-c.clientWidth;
7022 scrollChildIntoView : function(child, hscroll){
7023 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7027 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7028 * the new height may not be available immediately.
7029 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7030 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7031 * @param {Function} onComplete (optional) Function to call when animation completes
7032 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7033 * @return {Roo.Element} this
7035 autoHeight : function(animate, duration, onComplete, easing){
7036 var oldHeight = this.getHeight();
7038 this.setHeight(1); // force clipping
7039 setTimeout(function(){
7040 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7042 this.setHeight(height);
7044 if(typeof onComplete == "function"){
7048 this.setHeight(oldHeight); // restore original height
7049 this.setHeight(height, animate, duration, function(){
7051 if(typeof onComplete == "function") onComplete();
7052 }.createDelegate(this), easing);
7054 }.createDelegate(this), 0);
7059 * Returns true if this element is an ancestor of the passed element
7060 * @param {HTMLElement/String} el The element to check
7061 * @return {Boolean} True if this element is an ancestor of el, else false
7063 contains : function(el){
7064 if(!el){return false;}
7065 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7069 * Checks whether the element is currently visible using both visibility and display properties.
7070 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7071 * @return {Boolean} True if the element is currently visible, else false
7073 isVisible : function(deep) {
7074 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7075 if(deep !== true || !vis){
7078 var p = this.dom.parentNode;
7079 while(p && p.tagName.toLowerCase() != "body"){
7080 if(!Roo.fly(p, '_isVisible').isVisible()){
7089 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7090 * @param {String} selector The CSS selector
7091 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7092 * @return {CompositeElement/CompositeElementLite} The composite element
7094 select : function(selector, unique){
7095 return El.select(selector, unique, this.dom);
7099 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7100 * @param {String} selector The CSS selector
7101 * @return {Array} An array of the matched nodes
7103 query : function(selector, unique){
7104 return Roo.DomQuery.select(selector, this.dom);
7108 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7109 * @param {String} selector The CSS selector
7110 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7111 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7113 child : function(selector, returnDom){
7114 var n = Roo.DomQuery.selectNode(selector, this.dom);
7115 return returnDom ? n : Roo.get(n);
7119 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7120 * @param {String} selector The CSS selector
7121 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7122 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7124 down : function(selector, returnDom){
7125 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7126 return returnDom ? n : Roo.get(n);
7130 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7131 * @param {String} group The group the DD object is member of
7132 * @param {Object} config The DD config object
7133 * @param {Object} overrides An object containing methods to override/implement on the DD object
7134 * @return {Roo.dd.DD} The DD object
7136 initDD : function(group, config, overrides){
7137 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7138 return Roo.apply(dd, overrides);
7142 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7143 * @param {String} group The group the DDProxy object is member of
7144 * @param {Object} config The DDProxy config object
7145 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7146 * @return {Roo.dd.DDProxy} The DDProxy object
7148 initDDProxy : function(group, config, overrides){
7149 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7150 return Roo.apply(dd, overrides);
7154 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7155 * @param {String} group The group the DDTarget object is member of
7156 * @param {Object} config The DDTarget config object
7157 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7158 * @return {Roo.dd.DDTarget} The DDTarget object
7160 initDDTarget : function(group, config, overrides){
7161 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7162 return Roo.apply(dd, overrides);
7166 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7167 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7168 * @param {Boolean} visible Whether the element is visible
7169 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7170 * @return {Roo.Element} this
7172 setVisible : function(visible, animate){
7174 if(this.visibilityMode == El.DISPLAY){
7175 this.setDisplayed(visible);
7178 this.dom.style.visibility = visible ? "visible" : "hidden";
7181 // closure for composites
7183 var visMode = this.visibilityMode;
7185 this.setOpacity(.01);
7186 this.setVisible(true);
7188 this.anim({opacity: { to: (visible?1:0) }},
7189 this.preanim(arguments, 1),
7190 null, .35, 'easeIn', function(){
7192 if(visMode == El.DISPLAY){
7193 dom.style.display = "none";
7195 dom.style.visibility = "hidden";
7197 Roo.get(dom).setOpacity(1);
7205 * Returns true if display is not "none"
7208 isDisplayed : function() {
7209 return this.getStyle("display") != "none";
7213 * Toggles the element's visibility or display, depending on visibility mode.
7214 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7215 * @return {Roo.Element} this
7217 toggle : function(animate){
7218 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7223 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7224 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7225 * @return {Roo.Element} this
7227 setDisplayed : function(value) {
7228 if(typeof value == "boolean"){
7229 value = value ? this.originalDisplay : "none";
7231 this.setStyle("display", value);
7236 * Tries to focus the element. Any exceptions are caught and ignored.
7237 * @return {Roo.Element} this
7239 focus : function() {
7247 * Tries to blur the element. Any exceptions are caught and ignored.
7248 * @return {Roo.Element} this
7258 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7259 * @param {String/Array} className The CSS class to add, or an array of classes
7260 * @return {Roo.Element} this
7262 addClass : function(className){
7263 if(className instanceof Array){
7264 for(var i = 0, len = className.length; i < len; i++) {
7265 this.addClass(className[i]);
7268 if(className && !this.hasClass(className)){
7269 this.dom.className = this.dom.className + " " + className;
7276 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7277 * @param {String/Array} className The CSS class to add, or an array of classes
7278 * @return {Roo.Element} this
7280 radioClass : function(className){
7281 var siblings = this.dom.parentNode.childNodes;
7282 for(var i = 0; i < siblings.length; i++) {
7283 var s = siblings[i];
7284 if(s.nodeType == 1){
7285 Roo.get(s).removeClass(className);
7288 this.addClass(className);
7293 * Removes one or more CSS classes from the element.
7294 * @param {String/Array} className The CSS class to remove, or an array of classes
7295 * @return {Roo.Element} this
7297 removeClass : function(className){
7298 if(!className || !this.dom.className){
7301 if(className instanceof Array){
7302 for(var i = 0, len = className.length; i < len; i++) {
7303 this.removeClass(className[i]);
7306 if(this.hasClass(className)){
7307 var re = this.classReCache[className];
7309 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7310 this.classReCache[className] = re;
7312 this.dom.className =
7313 this.dom.className.replace(re, " ");
7323 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7324 * @param {String} className The CSS class to toggle
7325 * @return {Roo.Element} this
7327 toggleClass : function(className){
7328 if(this.hasClass(className)){
7329 this.removeClass(className);
7331 this.addClass(className);
7337 * Checks if the specified CSS class exists on this element's DOM node.
7338 * @param {String} className The CSS class to check for
7339 * @return {Boolean} True if the class exists, else false
7341 hasClass : function(className){
7342 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7346 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7347 * @param {String} oldClassName The CSS class to replace
7348 * @param {String} newClassName The replacement CSS class
7349 * @return {Roo.Element} this
7351 replaceClass : function(oldClassName, newClassName){
7352 this.removeClass(oldClassName);
7353 this.addClass(newClassName);
7358 * Returns an object with properties matching the styles requested.
7359 * For example, el.getStyles('color', 'font-size', 'width') might return
7360 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7361 * @param {String} style1 A style name
7362 * @param {String} style2 A style name
7363 * @param {String} etc.
7364 * @return {Object} The style object
7366 getStyles : function(){
7367 var a = arguments, len = a.length, r = {};
7368 for(var i = 0; i < len; i++){
7369 r[a[i]] = this.getStyle(a[i]);
7375 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7376 * @param {String} property The style property whose value is returned.
7377 * @return {String} The current value of the style property for this element.
7379 getStyle : function(){
7380 return view && view.getComputedStyle ?
7382 var el = this.dom, v, cs, camel;
7383 if(prop == 'float'){
7386 if(el.style && (v = el.style[prop])){
7389 if(cs = view.getComputedStyle(el, "")){
7390 if(!(camel = propCache[prop])){
7391 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7398 var el = this.dom, v, cs, camel;
7399 if(prop == 'opacity'){
7400 if(typeof el.style.filter == 'string'){
7401 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7403 var fv = parseFloat(m[1]);
7405 return fv ? fv / 100 : 0;
7410 }else if(prop == 'float'){
7411 prop = "styleFloat";
7413 if(!(camel = propCache[prop])){
7414 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7416 if(v = el.style[camel]){
7419 if(cs = el.currentStyle){
7427 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7428 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7429 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7430 * @return {Roo.Element} this
7432 setStyle : function(prop, value){
7433 if(typeof prop == "string"){
7435 if (prop == 'float') {
7436 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7441 if(!(camel = propCache[prop])){
7442 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7445 if(camel == 'opacity') {
7446 this.setOpacity(value);
7448 this.dom.style[camel] = value;
7451 for(var style in prop){
7452 if(typeof prop[style] != "function"){
7453 this.setStyle(style, prop[style]);
7461 * More flexible version of {@link #setStyle} for setting style properties.
7462 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7463 * a function which returns such a specification.
7464 * @return {Roo.Element} this
7466 applyStyles : function(style){
7467 Roo.DomHelper.applyStyles(this.dom, style);
7472 * 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).
7473 * @return {Number} The X position of the element
7476 return D.getX(this.dom);
7480 * 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).
7481 * @return {Number} The Y position of the element
7484 return D.getY(this.dom);
7488 * 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).
7489 * @return {Array} The XY position of the element
7492 return D.getXY(this.dom);
7496 * 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).
7497 * @param {Number} The X position of the element
7498 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7499 * @return {Roo.Element} this
7501 setX : function(x, animate){
7503 D.setX(this.dom, x);
7505 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7511 * 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).
7512 * @param {Number} The Y position of the element
7513 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7514 * @return {Roo.Element} this
7516 setY : function(y, animate){
7518 D.setY(this.dom, y);
7520 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7526 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7527 * @param {String} left The left CSS property value
7528 * @return {Roo.Element} this
7530 setLeft : function(left){
7531 this.setStyle("left", this.addUnits(left));
7536 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7537 * @param {String} top The top CSS property value
7538 * @return {Roo.Element} this
7540 setTop : function(top){
7541 this.setStyle("top", this.addUnits(top));
7546 * Sets the element's CSS right style.
7547 * @param {String} right The right CSS property value
7548 * @return {Roo.Element} this
7550 setRight : function(right){
7551 this.setStyle("right", this.addUnits(right));
7556 * Sets the element's CSS bottom style.
7557 * @param {String} bottom The bottom CSS property value
7558 * @return {Roo.Element} this
7560 setBottom : function(bottom){
7561 this.setStyle("bottom", this.addUnits(bottom));
7566 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7567 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7568 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7569 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7570 * @return {Roo.Element} this
7572 setXY : function(pos, animate){
7574 D.setXY(this.dom, pos);
7576 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7582 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7583 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7584 * @param {Number} x X value for new position (coordinates are page-based)
7585 * @param {Number} y Y value for new position (coordinates are page-based)
7586 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7587 * @return {Roo.Element} this
7589 setLocation : function(x, y, animate){
7590 this.setXY([x, y], this.preanim(arguments, 2));
7595 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7596 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7597 * @param {Number} x X value for new position (coordinates are page-based)
7598 * @param {Number} y Y value for new position (coordinates are page-based)
7599 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7600 * @return {Roo.Element} this
7602 moveTo : function(x, y, animate){
7603 this.setXY([x, y], this.preanim(arguments, 2));
7608 * Returns the region of the given element.
7609 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7610 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7612 getRegion : function(){
7613 return D.getRegion(this.dom);
7617 * Returns the offset height of the element
7618 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7619 * @return {Number} The element's height
7621 getHeight : function(contentHeight){
7622 var h = this.dom.offsetHeight || 0;
7623 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7627 * Returns the offset width of the element
7628 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7629 * @return {Number} The element's width
7631 getWidth : function(contentWidth){
7632 var w = this.dom.offsetWidth || 0;
7633 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7637 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7638 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7639 * if a height has not been set using CSS.
7642 getComputedHeight : function(){
7643 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7645 h = parseInt(this.getStyle('height'), 10) || 0;
7646 if(!this.isBorderBox()){
7647 h += this.getFrameWidth('tb');
7654 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7655 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7656 * if a width has not been set using CSS.
7659 getComputedWidth : function(){
7660 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7662 w = parseInt(this.getStyle('width'), 10) || 0;
7663 if(!this.isBorderBox()){
7664 w += this.getFrameWidth('lr');
7671 * Returns the size of the element.
7672 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7673 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7675 getSize : function(contentSize){
7676 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7680 * Returns the width and height of the viewport.
7681 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7683 getViewSize : function(){
7684 var d = this.dom, doc = document, aw = 0, ah = 0;
7685 if(d == doc || d == doc.body){
7686 return {width : D.getViewWidth(), height: D.getViewHeight()};
7689 width : d.clientWidth,
7690 height: d.clientHeight
7696 * Returns the value of the "value" attribute
7697 * @param {Boolean} asNumber true to parse the value as a number
7698 * @return {String/Number}
7700 getValue : function(asNumber){
7701 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7705 adjustWidth : function(width){
7706 if(typeof width == "number"){
7707 if(this.autoBoxAdjust && !this.isBorderBox()){
7708 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7718 adjustHeight : function(height){
7719 if(typeof height == "number"){
7720 if(this.autoBoxAdjust && !this.isBorderBox()){
7721 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7731 * Set the width of the element
7732 * @param {Number} width The new width
7733 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7734 * @return {Roo.Element} this
7736 setWidth : function(width, animate){
7737 width = this.adjustWidth(width);
7739 this.dom.style.width = this.addUnits(width);
7741 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7747 * Set the height of the element
7748 * @param {Number} height The new height
7749 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7750 * @return {Roo.Element} this
7752 setHeight : function(height, animate){
7753 height = this.adjustHeight(height);
7755 this.dom.style.height = this.addUnits(height);
7757 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7763 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7764 * @param {Number} width The new width
7765 * @param {Number} height The new height
7766 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7767 * @return {Roo.Element} this
7769 setSize : function(width, height, animate){
7770 if(typeof width == "object"){ // in case of object from getSize()
7771 height = width.height; width = width.width;
7773 width = this.adjustWidth(width); height = this.adjustHeight(height);
7775 this.dom.style.width = this.addUnits(width);
7776 this.dom.style.height = this.addUnits(height);
7778 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7784 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7785 * @param {Number} x X value for new position (coordinates are page-based)
7786 * @param {Number} y Y value for new position (coordinates are page-based)
7787 * @param {Number} width The new width
7788 * @param {Number} height The new height
7789 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7790 * @return {Roo.Element} this
7792 setBounds : function(x, y, width, height, animate){
7794 this.setSize(width, height);
7795 this.setLocation(x, y);
7797 width = this.adjustWidth(width); height = this.adjustHeight(height);
7798 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7799 this.preanim(arguments, 4), 'motion');
7805 * 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.
7806 * @param {Roo.lib.Region} region The region to fill
7807 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7808 * @return {Roo.Element} this
7810 setRegion : function(region, animate){
7811 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7816 * Appends an event handler
7818 * @param {String} eventName The type of event to append
7819 * @param {Function} fn The method the event invokes
7820 * @param {Object} scope (optional) The scope (this object) of the fn
7821 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7823 addListener : function(eventName, fn, scope, options){
7824 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7828 * Removes an event handler from this element
7829 * @param {String} eventName the type of event to remove
7830 * @param {Function} fn the method the event invokes
7831 * @return {Roo.Element} this
7833 removeListener : function(eventName, fn){
7834 Roo.EventManager.removeListener(this.dom, eventName, fn);
7839 * Removes all previous added listeners from this element
7840 * @return {Roo.Element} this
7842 removeAllListeners : function(){
7843 E.purgeElement(this.dom);
7847 relayEvent : function(eventName, observable){
7848 this.on(eventName, function(e){
7849 observable.fireEvent(eventName, e);
7854 * Set the opacity of the element
7855 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7856 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7857 * @return {Roo.Element} this
7859 setOpacity : function(opacity, animate){
7861 var s = this.dom.style;
7864 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7865 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7867 s.opacity = opacity;
7870 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7876 * Gets the left X coordinate
7877 * @param {Boolean} local True to get the local css position instead of page coordinate
7880 getLeft : function(local){
7884 return parseInt(this.getStyle("left"), 10) || 0;
7889 * Gets the right X coordinate of the element (element X position + element width)
7890 * @param {Boolean} local True to get the local css position instead of page coordinate
7893 getRight : function(local){
7895 return this.getX() + this.getWidth();
7897 return (this.getLeft(true) + this.getWidth()) || 0;
7902 * Gets the top Y coordinate
7903 * @param {Boolean} local True to get the local css position instead of page coordinate
7906 getTop : function(local) {
7910 return parseInt(this.getStyle("top"), 10) || 0;
7915 * Gets the bottom Y coordinate of the element (element Y position + element height)
7916 * @param {Boolean} local True to get the local css position instead of page coordinate
7919 getBottom : function(local){
7921 return this.getY() + this.getHeight();
7923 return (this.getTop(true) + this.getHeight()) || 0;
7928 * Initializes positioning on this element. If a desired position is not passed, it will make the
7929 * the element positioned relative IF it is not already positioned.
7930 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7931 * @param {Number} zIndex (optional) The zIndex to apply
7932 * @param {Number} x (optional) Set the page X position
7933 * @param {Number} y (optional) Set the page Y position
7935 position : function(pos, zIndex, x, y){
7937 if(this.getStyle('position') == 'static'){
7938 this.setStyle('position', 'relative');
7941 this.setStyle("position", pos);
7944 this.setStyle("z-index", zIndex);
7946 if(x !== undefined && y !== undefined){
7948 }else if(x !== undefined){
7950 }else if(y !== undefined){
7956 * Clear positioning back to the default when the document was loaded
7957 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7958 * @return {Roo.Element} this
7960 clearPositioning : function(value){
7968 "position" : "static"
7974 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7975 * snapshot before performing an update and then restoring the element.
7978 getPositioning : function(){
7979 var l = this.getStyle("left");
7980 var t = this.getStyle("top");
7982 "position" : this.getStyle("position"),
7984 "right" : l ? "" : this.getStyle("right"),
7986 "bottom" : t ? "" : this.getStyle("bottom"),
7987 "z-index" : this.getStyle("z-index")
7992 * Gets the width of the border(s) for the specified side(s)
7993 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7994 * passing lr would get the border (l)eft width + the border (r)ight width.
7995 * @return {Number} The width of the sides passed added together
7997 getBorderWidth : function(side){
7998 return this.addStyles(side, El.borders);
8002 * Gets the width of the padding(s) for the specified side(s)
8003 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8004 * passing lr would get the padding (l)eft + the padding (r)ight.
8005 * @return {Number} The padding of the sides passed added together
8007 getPadding : function(side){
8008 return this.addStyles(side, El.paddings);
8012 * Set positioning with an object returned by getPositioning().
8013 * @param {Object} posCfg
8014 * @return {Roo.Element} this
8016 setPositioning : function(pc){
8017 this.applyStyles(pc);
8018 if(pc.right == "auto"){
8019 this.dom.style.right = "";
8021 if(pc.bottom == "auto"){
8022 this.dom.style.bottom = "";
8028 fixDisplay : function(){
8029 if(this.getStyle("display") == "none"){
8030 this.setStyle("visibility", "hidden");
8031 this.setStyle("display", this.originalDisplay); // first try reverting to default
8032 if(this.getStyle("display") == "none"){ // if that fails, default to block
8033 this.setStyle("display", "block");
8039 * Quick set left and top adding default units
8040 * @param {String} left The left CSS property value
8041 * @param {String} top The top CSS property value
8042 * @return {Roo.Element} this
8044 setLeftTop : function(left, top){
8045 this.dom.style.left = this.addUnits(left);
8046 this.dom.style.top = this.addUnits(top);
8051 * Move this element relative to its current position.
8052 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8053 * @param {Number} distance How far to move the element in pixels
8054 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8055 * @return {Roo.Element} this
8057 move : function(direction, distance, animate){
8058 var xy = this.getXY();
8059 direction = direction.toLowerCase();
8063 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8067 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8072 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8077 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8084 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8085 * @return {Roo.Element} this
8088 if(!this.isClipped){
8089 this.isClipped = true;
8090 this.originalClip = {
8091 "o": this.getStyle("overflow"),
8092 "x": this.getStyle("overflow-x"),
8093 "y": this.getStyle("overflow-y")
8095 this.setStyle("overflow", "hidden");
8096 this.setStyle("overflow-x", "hidden");
8097 this.setStyle("overflow-y", "hidden");
8103 * Return clipping (overflow) to original clipping before clip() was called
8104 * @return {Roo.Element} this
8106 unclip : function(){
8108 this.isClipped = false;
8109 var o = this.originalClip;
8110 if(o.o){this.setStyle("overflow", o.o);}
8111 if(o.x){this.setStyle("overflow-x", o.x);}
8112 if(o.y){this.setStyle("overflow-y", o.y);}
8119 * Gets the x,y coordinates specified by the anchor position on the element.
8120 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8121 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8122 * {width: (target width), height: (target height)} (defaults to the element's current size)
8123 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8124 * @return {Array} [x, y] An array containing the element's x and y coordinates
8126 getAnchorXY : function(anchor, local, s){
8127 //Passing a different size is useful for pre-calculating anchors,
8128 //especially for anchored animations that change the el size.
8130 var w, h, vp = false;
8133 if(d == document.body || d == document){
8135 w = D.getViewWidth(); h = D.getViewHeight();
8137 w = this.getWidth(); h = this.getHeight();
8140 w = s.width; h = s.height;
8142 var x = 0, y = 0, r = Math.round;
8143 switch((anchor || "tl").toLowerCase()){
8185 var sc = this.getScroll();
8186 return [x + sc.left, y + sc.top];
8188 //Add the element's offset xy
8189 var o = this.getXY();
8190 return [x+o[0], y+o[1]];
8194 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8195 * supported position values.
8196 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8197 * @param {String} position The position to align to.
8198 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8199 * @return {Array} [x, y]
8201 getAlignToXY : function(el, p, o){
8205 throw "Element.alignTo with an element that doesn't exist";
8207 var c = false; //constrain to viewport
8208 var p1 = "", p2 = "";
8215 }else if(p.indexOf("-") == -1){
8218 p = p.toLowerCase();
8219 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8221 throw "Element.alignTo with an invalid alignment " + p;
8223 p1 = m[1]; p2 = m[2]; c = !!m[3];
8225 //Subtract the aligned el's internal xy from the target's offset xy
8226 //plus custom offset to get the aligned el's new offset xy
8227 var a1 = this.getAnchorXY(p1, true);
8228 var a2 = el.getAnchorXY(p2, false);
8229 var x = a2[0] - a1[0] + o[0];
8230 var y = a2[1] - a1[1] + o[1];
8232 //constrain the aligned el to viewport if necessary
8233 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8234 // 5px of margin for ie
8235 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8237 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8238 //perpendicular to the vp border, allow the aligned el to slide on that border,
8239 //otherwise swap the aligned el to the opposite border of the target.
8240 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8241 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8242 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8243 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8246 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8247 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8249 if((x+w) > dw + scrollX){
8250 x = swapX ? r.left-w : dw+scrollX-w;
8253 x = swapX ? r.right : scrollX;
8255 if((y+h) > dh + scrollY){
8256 y = swapY ? r.top-h : dh+scrollY-h;
8259 y = swapY ? r.bottom : scrollY;
8266 getConstrainToXY : function(){
8267 var os = {top:0, left:0, bottom:0, right: 0};
8269 return function(el, local, offsets, proposedXY){
8271 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8273 var vw, vh, vx = 0, vy = 0;
8274 if(el.dom == document.body || el.dom == document){
8275 vw = Roo.lib.Dom.getViewWidth();
8276 vh = Roo.lib.Dom.getViewHeight();
8278 vw = el.dom.clientWidth;
8279 vh = el.dom.clientHeight;
8281 var vxy = el.getXY();
8287 var s = el.getScroll();
8289 vx += offsets.left + s.left;
8290 vy += offsets.top + s.top;
8292 vw -= offsets.right;
8293 vh -= offsets.bottom;
8298 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8299 var x = xy[0], y = xy[1];
8300 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8302 // only move it if it needs it
8305 // first validate right/bottom
8314 // then make sure top/left isn't negative
8323 return moved ? [x, y] : false;
8328 adjustForConstraints : function(xy, parent, offsets){
8329 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8333 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8334 * document it aligns it to the viewport.
8335 * The position parameter is optional, and can be specified in any one of the following formats:
8337 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8338 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8339 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8340 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8341 * <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
8342 * element's anchor point, and the second value is used as the target's anchor point.</li>
8344 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8345 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8346 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8347 * that specified in order to enforce the viewport constraints.
8348 * Following are all of the supported anchor positions:
8351 ----- -----------------------------
8352 tl The top left corner (default)
8353 t The center of the top edge
8354 tr The top right corner
8355 l The center of the left edge
8356 c In the center of the element
8357 r The center of the right edge
8358 bl The bottom left corner
8359 b The center of the bottom edge
8360 br The bottom right corner
8364 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8365 el.alignTo("other-el");
8367 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8368 el.alignTo("other-el", "tr?");
8370 // align the bottom right corner of el with the center left edge of other-el
8371 el.alignTo("other-el", "br-l?");
8373 // align the center of el with the bottom left corner of other-el and
8374 // adjust the x position by -6 pixels (and the y position by 0)
8375 el.alignTo("other-el", "c-bl", [-6, 0]);
8377 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8378 * @param {String} position The position to align to.
8379 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8380 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8381 * @return {Roo.Element} this
8383 alignTo : function(element, position, offsets, animate){
8384 var xy = this.getAlignToXY(element, position, offsets);
8385 this.setXY(xy, this.preanim(arguments, 3));
8390 * Anchors an element to another element and realigns it when the window is resized.
8391 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8392 * @param {String} position The position to align to.
8393 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8394 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8395 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8396 * is a number, it is used as the buffer delay (defaults to 50ms).
8397 * @param {Function} callback The function to call after the animation finishes
8398 * @return {Roo.Element} this
8400 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8401 var action = function(){
8402 this.alignTo(el, alignment, offsets, animate);
8403 Roo.callback(callback, this);
8405 Roo.EventManager.onWindowResize(action, this);
8406 var tm = typeof monitorScroll;
8407 if(tm != 'undefined'){
8408 Roo.EventManager.on(window, 'scroll', action, this,
8409 {buffer: tm == 'number' ? monitorScroll : 50});
8411 action.call(this); // align immediately
8415 * Clears any opacity settings from this element. Required in some cases for IE.
8416 * @return {Roo.Element} this
8418 clearOpacity : function(){
8419 if (window.ActiveXObject) {
8420 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8421 this.dom.style.filter = "";
8424 this.dom.style.opacity = "";
8425 this.dom.style["-moz-opacity"] = "";
8426 this.dom.style["-khtml-opacity"] = "";
8432 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8433 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8434 * @return {Roo.Element} this
8436 hide : function(animate){
8437 this.setVisible(false, this.preanim(arguments, 0));
8442 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8443 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8444 * @return {Roo.Element} this
8446 show : function(animate){
8447 this.setVisible(true, this.preanim(arguments, 0));
8452 * @private Test if size has a unit, otherwise appends the default
8454 addUnits : function(size){
8455 return Roo.Element.addUnits(size, this.defaultUnit);
8459 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8460 * @return {Roo.Element} this
8462 beginMeasure : function(){
8464 if(el.offsetWidth || el.offsetHeight){
8465 return this; // offsets work already
8468 var p = this.dom, b = document.body; // start with this element
8469 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8470 var pe = Roo.get(p);
8471 if(pe.getStyle('display') == 'none'){
8472 changed.push({el: p, visibility: pe.getStyle("visibility")});
8473 p.style.visibility = "hidden";
8474 p.style.display = "block";
8478 this._measureChanged = changed;
8484 * Restores displays to before beginMeasure was called
8485 * @return {Roo.Element} this
8487 endMeasure : function(){
8488 var changed = this._measureChanged;
8490 for(var i = 0, len = changed.length; i < len; i++) {
8492 r.el.style.visibility = r.visibility;
8493 r.el.style.display = "none";
8495 this._measureChanged = null;
8501 * Update the innerHTML of this element, optionally searching for and processing scripts
8502 * @param {String} html The new HTML
8503 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8504 * @param {Function} callback For async script loading you can be noticed when the update completes
8505 * @return {Roo.Element} this
8507 update : function(html, loadScripts, callback){
8508 if(typeof html == "undefined"){
8511 if(loadScripts !== true){
8512 this.dom.innerHTML = html;
8513 if(typeof callback == "function"){
8521 html += '<span id="' + id + '"></span>';
8523 E.onAvailable(id, function(){
8524 var hd = document.getElementsByTagName("head")[0];
8525 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8526 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8527 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8530 while(match = re.exec(html)){
8531 var attrs = match[1];
8532 var srcMatch = attrs ? attrs.match(srcRe) : false;
8533 if(srcMatch && srcMatch[2]){
8534 var s = document.createElement("script");
8535 s.src = srcMatch[2];
8536 var typeMatch = attrs.match(typeRe);
8537 if(typeMatch && typeMatch[2]){
8538 s.type = typeMatch[2];
8541 }else if(match[2] && match[2].length > 0){
8542 if(window.execScript) {
8543 window.execScript(match[2]);
8551 window.eval(match[2]);
8555 var el = document.getElementById(id);
8556 if(el){el.parentNode.removeChild(el);}
8557 if(typeof callback == "function"){
8561 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8566 * Direct access to the UpdateManager update() method (takes the same parameters).
8567 * @param {String/Function} url The url for this request or a function to call to get the url
8568 * @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}
8569 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8570 * @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.
8571 * @return {Roo.Element} this
8574 var um = this.getUpdateManager();
8575 um.update.apply(um, arguments);
8580 * Gets this element's UpdateManager
8581 * @return {Roo.UpdateManager} The UpdateManager
8583 getUpdateManager : function(){
8584 if(!this.updateManager){
8585 this.updateManager = new Roo.UpdateManager(this);
8587 return this.updateManager;
8591 * Disables text selection for this element (normalized across browsers)
8592 * @return {Roo.Element} this
8594 unselectable : function(){
8595 this.dom.unselectable = "on";
8596 this.swallowEvent("selectstart", true);
8597 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8598 this.addClass("x-unselectable");
8603 * Calculates the x, y to center this element on the screen
8604 * @return {Array} The x, y values [x, y]
8606 getCenterXY : function(){
8607 return this.getAlignToXY(document, 'c-c');
8611 * Centers the Element in either the viewport, or another Element.
8612 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8614 center : function(centerIn){
8615 this.alignTo(centerIn || document, 'c-c');
8620 * Tests various css rules/browsers to determine if this element uses a border box
8623 isBorderBox : function(){
8624 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8628 * Return a box {x, y, width, height} that can be used to set another elements
8629 * size/location to match this element.
8630 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8631 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8632 * @return {Object} box An object in the format {x, y, width, height}
8634 getBox : function(contentBox, local){
8639 var left = parseInt(this.getStyle("left"), 10) || 0;
8640 var top = parseInt(this.getStyle("top"), 10) || 0;
8643 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8645 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8647 var l = this.getBorderWidth("l")+this.getPadding("l");
8648 var r = this.getBorderWidth("r")+this.getPadding("r");
8649 var t = this.getBorderWidth("t")+this.getPadding("t");
8650 var b = this.getBorderWidth("b")+this.getPadding("b");
8651 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)};
8653 bx.right = bx.x + bx.width;
8654 bx.bottom = bx.y + bx.height;
8659 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8660 for more information about the sides.
8661 * @param {String} sides
8664 getFrameWidth : function(sides, onlyContentBox){
8665 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8669 * 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.
8670 * @param {Object} box The box to fill {x, y, width, height}
8671 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8672 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8673 * @return {Roo.Element} this
8675 setBox : function(box, adjust, animate){
8676 var w = box.width, h = box.height;
8677 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8678 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8679 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8681 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8686 * Forces the browser to repaint this element
8687 * @return {Roo.Element} this
8689 repaint : function(){
8691 this.addClass("x-repaint");
8692 setTimeout(function(){
8693 Roo.get(dom).removeClass("x-repaint");
8699 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8700 * then it returns the calculated width of the sides (see getPadding)
8701 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8702 * @return {Object/Number}
8704 getMargins : function(side){
8707 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8708 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8709 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8710 right: parseInt(this.getStyle("margin-right"), 10) || 0
8713 return this.addStyles(side, El.margins);
8718 addStyles : function(sides, styles){
8720 for(var i = 0, len = sides.length; i < len; i++){
8721 v = this.getStyle(styles[sides.charAt(i)]);
8723 w = parseInt(v, 10);
8731 * Creates a proxy element of this element
8732 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8733 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8734 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8735 * @return {Roo.Element} The new proxy element
8737 createProxy : function(config, renderTo, matchBox){
8739 renderTo = Roo.getDom(renderTo);
8741 renderTo = document.body;
8743 config = typeof config == "object" ?
8744 config : {tag : "div", cls: config};
8745 var proxy = Roo.DomHelper.append(renderTo, config, true);
8747 proxy.setBox(this.getBox());
8753 * Puts a mask over this element to disable user interaction. Requires core.css.
8754 * This method can only be applied to elements which accept child nodes.
8755 * @param {String} msg (optional) A message to display in the mask
8756 * @param {String} msgCls (optional) A css class to apply to the msg element
8757 * @return {Element} The mask element
8759 mask : function(msg, msgCls){
8760 if(this.getStyle("position") == "static"){
8761 this.setStyle("position", "relative");
8764 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8766 this.addClass("x-masked");
8767 this._mask.setDisplayed(true);
8768 if(typeof msg == 'string'){
8770 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8772 var mm = this._maskMsg;
8773 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8774 mm.dom.firstChild.innerHTML = msg;
8775 mm.setDisplayed(true);
8778 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8779 this._mask.setHeight(this.getHeight());
8785 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8786 * it is cached for reuse.
8788 unmask : function(removeEl){
8790 if(removeEl === true){
8791 this._mask.remove();
8794 this._maskMsg.remove();
8795 delete this._maskMsg;
8798 this._mask.setDisplayed(false);
8800 this._maskMsg.setDisplayed(false);
8804 this.removeClass("x-masked");
8808 * Returns true if this element is masked
8811 isMasked : function(){
8812 return this._mask && this._mask.isVisible();
8816 * Creates an iframe shim for this element to keep selects and other windowed objects from
8818 * @return {Roo.Element} The new shim element
8820 createShim : function(){
8821 var el = document.createElement('iframe');
8822 el.frameBorder = 'no';
8823 el.className = 'roo-shim';
8824 if(Roo.isIE && Roo.isSecure){
8825 el.src = Roo.SSL_SECURE_URL;
8827 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8828 shim.autoBoxAdjust = false;
8833 * Removes this element from the DOM and deletes it from the cache
8835 remove : function(){
8836 if(this.dom.parentNode){
8837 this.dom.parentNode.removeChild(this.dom);
8839 delete El.cache[this.dom.id];
8843 * Sets up event handlers to add and remove a css class when the mouse is over this element
8844 * @param {String} className
8845 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8846 * mouseout events for children elements
8847 * @return {Roo.Element} this
8849 addClassOnOver : function(className, preventFlicker){
8850 this.on("mouseover", function(){
8851 Roo.fly(this, '_internal').addClass(className);
8853 var removeFn = function(e){
8854 if(preventFlicker !== true || !e.within(this, true)){
8855 Roo.fly(this, '_internal').removeClass(className);
8858 this.on("mouseout", removeFn, this.dom);
8863 * Sets up event handlers to add and remove a css class when this element has the focus
8864 * @param {String} className
8865 * @return {Roo.Element} this
8867 addClassOnFocus : function(className){
8868 this.on("focus", function(){
8869 Roo.fly(this, '_internal').addClass(className);
8871 this.on("blur", function(){
8872 Roo.fly(this, '_internal').removeClass(className);
8877 * 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)
8878 * @param {String} className
8879 * @return {Roo.Element} this
8881 addClassOnClick : function(className){
8883 this.on("mousedown", function(){
8884 Roo.fly(dom, '_internal').addClass(className);
8885 var d = Roo.get(document);
8886 var fn = function(){
8887 Roo.fly(dom, '_internal').removeClass(className);
8888 d.removeListener("mouseup", fn);
8890 d.on("mouseup", fn);
8896 * Stops the specified event from bubbling and optionally prevents the default action
8897 * @param {String} eventName
8898 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8899 * @return {Roo.Element} this
8901 swallowEvent : function(eventName, preventDefault){
8902 var fn = function(e){
8903 e.stopPropagation();
8908 if(eventName instanceof Array){
8909 for(var i = 0, len = eventName.length; i < len; i++){
8910 this.on(eventName[i], fn);
8914 this.on(eventName, fn);
8921 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8924 * Sizes this element to its parent element's dimensions performing
8925 * neccessary box adjustments.
8926 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8927 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8928 * @return {Roo.Element} this
8930 fitToParent : function(monitorResize, targetParent) {
8931 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8932 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8933 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8936 var p = Roo.get(targetParent || this.dom.parentNode);
8937 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8938 if (monitorResize === true) {
8939 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8940 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8946 * Gets the next sibling, skipping text nodes
8947 * @return {HTMLElement} The next sibling or null
8949 getNextSibling : function(){
8950 var n = this.dom.nextSibling;
8951 while(n && n.nodeType != 1){
8958 * Gets the previous sibling, skipping text nodes
8959 * @return {HTMLElement} The previous sibling or null
8961 getPrevSibling : function(){
8962 var n = this.dom.previousSibling;
8963 while(n && n.nodeType != 1){
8964 n = n.previousSibling;
8971 * Appends the passed element(s) to this element
8972 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8973 * @return {Roo.Element} this
8975 appendChild: function(el){
8982 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8983 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8984 * automatically generated with the specified attributes.
8985 * @param {HTMLElement} insertBefore (optional) a child element of this element
8986 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8987 * @return {Roo.Element} The new child element
8989 createChild: function(config, insertBefore, returnDom){
8990 config = config || {tag:'div'};
8992 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8994 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8998 * Appends this element to the passed element
8999 * @param {String/HTMLElement/Element} el The new parent element
9000 * @return {Roo.Element} this
9002 appendTo: function(el){
9003 el = Roo.getDom(el);
9004 el.appendChild(this.dom);
9009 * Inserts this element before the passed element in the DOM
9010 * @param {String/HTMLElement/Element} el The element to insert before
9011 * @return {Roo.Element} this
9013 insertBefore: function(el){
9014 el = Roo.getDom(el);
9015 el.parentNode.insertBefore(this.dom, el);
9020 * Inserts this element after the passed element in the DOM
9021 * @param {String/HTMLElement/Element} el The element to insert after
9022 * @return {Roo.Element} this
9024 insertAfter: function(el){
9025 el = Roo.getDom(el);
9026 el.parentNode.insertBefore(this.dom, el.nextSibling);
9031 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9032 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9033 * @return {Roo.Element} The new child
9035 insertFirst: function(el, returnDom){
9037 if(typeof el == 'object' && !el.nodeType){ // dh config
9038 return this.createChild(el, this.dom.firstChild, returnDom);
9040 el = Roo.getDom(el);
9041 this.dom.insertBefore(el, this.dom.firstChild);
9042 return !returnDom ? Roo.get(el) : el;
9047 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9048 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9049 * @param {String} where (optional) 'before' or 'after' defaults to before
9050 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9051 * @return {Roo.Element} the inserted Element
9053 insertSibling: function(el, where, returnDom){
9054 where = where ? where.toLowerCase() : 'before';
9056 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9058 if(typeof el == 'object' && !el.nodeType){ // dh config
9059 if(where == 'after' && !this.dom.nextSibling){
9060 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9062 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9066 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9067 where == 'before' ? this.dom : this.dom.nextSibling);
9076 * Creates and wraps this element with another element
9077 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9078 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9079 * @return {HTMLElement/Element} The newly created wrapper element
9081 wrap: function(config, returnDom){
9083 config = {tag: "div"};
9085 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9086 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9091 * Replaces the passed element with this element
9092 * @param {String/HTMLElement/Element} el The element to replace
9093 * @return {Roo.Element} this
9095 replace: function(el){
9097 this.insertBefore(el);
9103 * Inserts an html fragment into this element
9104 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9105 * @param {String} html The HTML fragment
9106 * @param {Boolean} returnEl True to return an Roo.Element
9107 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9109 insertHtml : function(where, html, returnEl){
9110 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9111 return returnEl ? Roo.get(el) : el;
9115 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9116 * @param {Object} o The object with the attributes
9117 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9118 * @return {Roo.Element} this
9120 set : function(o, useSet){
9122 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9124 if(attr == "style" || typeof o[attr] == "function") continue;
9126 el.className = o["cls"];
9128 if(useSet) el.setAttribute(attr, o[attr]);
9129 else el[attr] = o[attr];
9133 Roo.DomHelper.applyStyles(el, o.style);
9139 * Convenience method for constructing a KeyMap
9140 * @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:
9141 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9142 * @param {Function} fn The function to call
9143 * @param {Object} scope (optional) The scope of the function
9144 * @return {Roo.KeyMap} The KeyMap created
9146 addKeyListener : function(key, fn, scope){
9148 if(typeof key != "object" || key instanceof Array){
9164 return new Roo.KeyMap(this, config);
9168 * Creates a KeyMap for this element
9169 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9170 * @return {Roo.KeyMap} The KeyMap created
9172 addKeyMap : function(config){
9173 return new Roo.KeyMap(this, config);
9177 * Returns true if this element is scrollable.
9180 isScrollable : function(){
9182 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9186 * 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().
9187 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9188 * @param {Number} value The new scroll value
9189 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9190 * @return {Element} this
9193 scrollTo : function(side, value, animate){
9194 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9196 this.dom[prop] = value;
9198 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9199 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9205 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9206 * within this element's scrollable range.
9207 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9208 * @param {Number} distance How far to scroll the element in pixels
9209 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9210 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9211 * was scrolled as far as it could go.
9213 scroll : function(direction, distance, animate){
9214 if(!this.isScrollable()){
9218 var l = el.scrollLeft, t = el.scrollTop;
9219 var w = el.scrollWidth, h = el.scrollHeight;
9220 var cw = el.clientWidth, ch = el.clientHeight;
9221 direction = direction.toLowerCase();
9222 var scrolled = false;
9223 var a = this.preanim(arguments, 2);
9228 var v = Math.min(l + distance, w-cw);
9229 this.scrollTo("left", v, a);
9236 var v = Math.max(l - distance, 0);
9237 this.scrollTo("left", v, a);
9245 var v = Math.max(t - distance, 0);
9246 this.scrollTo("top", v, a);
9254 var v = Math.min(t + distance, h-ch);
9255 this.scrollTo("top", v, a);
9264 * Translates the passed page coordinates into left/top css values for this element
9265 * @param {Number/Array} x The page x or an array containing [x, y]
9266 * @param {Number} y The page y
9267 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9269 translatePoints : function(x, y){
9270 if(typeof x == 'object' || x instanceof Array){
9273 var p = this.getStyle('position');
9274 var o = this.getXY();
9276 var l = parseInt(this.getStyle('left'), 10);
9277 var t = parseInt(this.getStyle('top'), 10);
9280 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9283 t = (p == "relative") ? 0 : this.dom.offsetTop;
9286 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9290 * Returns the current scroll position of the element.
9291 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9293 getScroll : function(){
9294 var d = this.dom, doc = document;
9295 if(d == doc || d == doc.body){
9296 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9297 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9298 return {left: l, top: t};
9300 return {left: d.scrollLeft, top: d.scrollTop};
9305 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9306 * are convert to standard 6 digit hex color.
9307 * @param {String} attr The css attribute
9308 * @param {String} defaultValue The default value to use when a valid color isn't found
9309 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9312 getColor : function(attr, defaultValue, prefix){
9313 var v = this.getStyle(attr);
9314 if(!v || v == "transparent" || v == "inherit") {
9315 return defaultValue;
9317 var color = typeof prefix == "undefined" ? "#" : prefix;
9318 if(v.substr(0, 4) == "rgb("){
9319 var rvs = v.slice(4, v.length -1).split(",");
9320 for(var i = 0; i < 3; i++){
9321 var h = parseInt(rvs[i]).toString(16);
9328 if(v.substr(0, 1) == "#"){
9330 for(var i = 1; i < 4; i++){
9331 var c = v.charAt(i);
9334 }else if(v.length == 7){
9335 color += v.substr(1);
9339 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9343 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9344 * gradient background, rounded corners and a 4-way shadow.
9345 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9346 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9347 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9348 * @return {Roo.Element} this
9350 boxWrap : function(cls){
9351 cls = cls || 'x-box';
9352 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9353 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9358 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9359 * @param {String} namespace The namespace in which to look for the attribute
9360 * @param {String} name The attribute name
9361 * @return {String} The attribute value
9363 getAttributeNS : Roo.isIE ? function(ns, name){
9365 var type = typeof d[ns+":"+name];
9366 if(type != 'undefined' && type != 'unknown'){
9367 return d[ns+":"+name];
9370 } : function(ns, name){
9372 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9376 var ep = El.prototype;
9379 * Appends an event handler (Shorthand for addListener)
9380 * @param {String} eventName The type of event to append
9381 * @param {Function} fn The method the event invokes
9382 * @param {Object} scope (optional) The scope (this object) of the fn
9383 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9386 ep.on = ep.addListener;
9388 ep.mon = ep.addListener;
9391 * Removes an event handler from this element (shorthand for removeListener)
9392 * @param {String} eventName the type of event to remove
9393 * @param {Function} fn the method the event invokes
9394 * @return {Roo.Element} this
9397 ep.un = ep.removeListener;
9400 * true to automatically adjust width and height settings for box-model issues (default to true)
9402 ep.autoBoxAdjust = true;
9405 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9408 El.addUnits = function(v, defaultUnit){
9409 if(v === "" || v == "auto"){
9412 if(v === undefined){
9415 if(typeof v == "number" || !El.unitPattern.test(v)){
9416 return v + (defaultUnit || 'px');
9421 // special markup used throughout Roo when box wrapping elements
9422 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>';
9424 * Visibility mode constant - Use visibility to hide element
9430 * Visibility mode constant - Use display to hide element
9436 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9437 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9438 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9450 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9451 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9452 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9453 * @return {Element} The Element object
9456 El.get = function(el){
9458 if(!el){ return null; }
9459 if(typeof el == "string"){ // element id
9460 if(!(elm = document.getElementById(el))){
9463 if(ex = El.cache[el]){
9466 ex = El.cache[el] = new El(elm);
9469 }else if(el.tagName){ // dom element
9473 if(ex = El.cache[id]){
9476 ex = El.cache[id] = new El(el);
9479 }else if(el instanceof El){
9481 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9482 // catch case where it hasn't been appended
9483 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9486 }else if(el.isComposite){
9488 }else if(el instanceof Array){
9489 return El.select(el);
9490 }else if(el == document){
9491 // create a bogus element object representing the document object
9493 var f = function(){};
9494 f.prototype = El.prototype;
9496 docEl.dom = document;
9504 El.uncache = function(el){
9505 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9507 delete El.cache[a[i].id || a[i]];
9513 // Garbage collection - uncache elements/purge listeners on orphaned elements
9514 // so we don't hold a reference and cause the browser to retain them
9515 El.garbageCollect = function(){
9516 if(!Roo.enableGarbageCollector){
9517 clearInterval(El.collectorThread);
9520 for(var eid in El.cache){
9521 var el = El.cache[eid], d = el.dom;
9522 // -------------------------------------------------------
9523 // Determining what is garbage:
9524 // -------------------------------------------------------
9526 // dom node is null, definitely garbage
9527 // -------------------------------------------------------
9529 // no parentNode == direct orphan, definitely garbage
9530 // -------------------------------------------------------
9531 // !d.offsetParent && !document.getElementById(eid)
9532 // display none elements have no offsetParent so we will
9533 // also try to look it up by it's id. However, check
9534 // offsetParent first so we don't do unneeded lookups.
9535 // This enables collection of elements that are not orphans
9536 // directly, but somewhere up the line they have an orphan
9538 // -------------------------------------------------------
9539 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9540 delete El.cache[eid];
9541 if(d && Roo.enableListenerCollection){
9547 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9551 El.Flyweight = function(dom){
9554 El.Flyweight.prototype = El.prototype;
9556 El._flyweights = {};
9558 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9559 * the dom node can be overwritten by other code.
9560 * @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
9566 El.fly = function(el, named){
9567 named = named || '_global';
9568 el = Roo.getDom(el);
9572 if(!El._flyweights[named]){
9573 El._flyweights[named] = new El.Flyweight();
9575 El._flyweights[named].dom = el;
9576 return El._flyweights[named];
9580 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9581 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9582 * Shorthand of {@link Roo.Element#get}
9583 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9584 * @return {Element} The Element object
9590 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9591 * the dom node can be overwritten by other code.
9592 * Shorthand of {@link Roo.Element#fly}
9593 * @param {String/HTMLElement} el The dom node or id
9594 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9595 * prevent conflicts (e.g. internally Roo uses "_internal")
9597 * @return {Element} The shared Element object
9603 // speedy lookup for elements never to box adjust
9604 var noBoxAdjust = Roo.isStrict ? {
9607 input:1, select:1, textarea:1
9609 if(Roo.isIE || Roo.isGecko){
9610 noBoxAdjust['button'] = 1;
9614 Roo.EventManager.on(window, 'unload', function(){
9616 delete El._flyweights;
9624 Roo.Element.selectorFunction = Roo.DomQuery.select;
9627 Roo.Element.select = function(selector, unique, root){
9629 if(typeof selector == "string"){
9630 els = Roo.Element.selectorFunction(selector, root);
9631 }else if(selector.length !== undefined){
9634 throw "Invalid selector";
9636 if(unique === true){
9637 return new Roo.CompositeElement(els);
9639 return new Roo.CompositeElementLite(els);
9643 * Selects elements based on the passed CSS selector to enable working on them as 1.
9644 * @param {String/Array} selector The CSS selector or an array of elements
9645 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9646 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9647 * @return {CompositeElementLite/CompositeElement}
9651 Roo.select = Roo.Element.select;
9668 * Ext JS Library 1.1.1
9669 * Copyright(c) 2006-2007, Ext JS, LLC.
9671 * Originally Released Under LGPL - original licence link has changed is not relivant.
9674 * <script type="text/javascript">
9679 //Notifies Element that fx methods are available
9680 Roo.enableFx = true;
9684 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9685 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9686 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9687 * Element effects to work.</p><br/>
9689 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9690 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9691 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9692 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9693 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9694 * expected results and should be done with care.</p><br/>
9696 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9697 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9700 ----- -----------------------------
9701 tl The top left corner
9702 t The center of the top edge
9703 tr The top right corner
9704 l The center of the left edge
9705 r The center of the right edge
9706 bl The bottom left corner
9707 b The center of the bottom edge
9708 br The bottom right corner
9710 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9711 * below are common options that can be passed to any Fx method.</b>
9712 * @cfg {Function} callback A function called when the effect is finished
9713 * @cfg {Object} scope The scope of the effect function
9714 * @cfg {String} easing A valid Easing value for the effect
9715 * @cfg {String} afterCls A css class to apply after the effect
9716 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9717 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9718 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9719 * effects that end with the element being visually hidden, ignored otherwise)
9720 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9721 * a function which returns such a specification that will be applied to the Element after the effect finishes
9722 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9723 * @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
9724 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9728 * Slides the element into view. An anchor point can be optionally passed to set the point of
9729 * origin for the slide effect. This function automatically handles wrapping the element with
9730 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9733 // default: slide the element in from the top
9736 // custom: slide the element in from the right with a 2-second duration
9737 el.slideIn('r', { duration: 2 });
9739 // common config options shown with default values
9745 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9746 * @param {Object} options (optional) Object literal with any of the Fx config options
9747 * @return {Roo.Element} The Element
9749 slideIn : function(anchor, o){
9750 var el = this.getFxEl();
9753 el.queueFx(o, function(){
9755 anchor = anchor || "t";
9757 // fix display to visibility
9760 // restore values after effect
9761 var r = this.getFxRestore();
9762 var b = this.getBox();
9763 // fixed size for slide
9767 var wrap = this.fxWrap(r.pos, o, "hidden");
9769 var st = this.dom.style;
9770 st.visibility = "visible";
9771 st.position = "absolute";
9773 // clear out temp styles after slide and unwrap
9774 var after = function(){
9775 el.fxUnwrap(wrap, r.pos, o);
9777 st.height = r.height;
9780 // time to calc the positions
9781 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9783 switch(anchor.toLowerCase()){
9785 wrap.setSize(b.width, 0);
9786 st.left = st.bottom = "0";
9790 wrap.setSize(0, b.height);
9791 st.right = st.top = "0";
9795 wrap.setSize(0, b.height);
9797 st.left = st.top = "0";
9798 a = {width: bw, points: pt};
9801 wrap.setSize(b.width, 0);
9802 wrap.setY(b.bottom);
9803 st.left = st.top = "0";
9804 a = {height: bh, points: pt};
9808 st.right = st.bottom = "0";
9809 a = {width: bw, height: bh};
9813 wrap.setY(b.y+b.height);
9814 st.right = st.top = "0";
9815 a = {width: bw, height: bh, points: pt};
9819 wrap.setXY([b.right, b.bottom]);
9820 st.left = st.top = "0";
9821 a = {width: bw, height: bh, points: pt};
9825 wrap.setX(b.x+b.width);
9826 st.left = st.bottom = "0";
9827 a = {width: bw, height: bh, points: pt};
9830 this.dom.style.visibility = "visible";
9833 arguments.callee.anim = wrap.fxanim(a,
9843 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9844 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9845 * 'hidden') but block elements will still take up space in the document. The element must be removed
9846 * from the DOM using the 'remove' config option if desired. This function automatically handles
9847 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9850 // default: slide the element out to the top
9853 // custom: slide the element out to the right with a 2-second duration
9854 el.slideOut('r', { duration: 2 });
9856 // common config options shown with default values
9864 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9865 * @param {Object} options (optional) Object literal with any of the Fx config options
9866 * @return {Roo.Element} The Element
9868 slideOut : function(anchor, o){
9869 var el = this.getFxEl();
9872 el.queueFx(o, function(){
9874 anchor = anchor || "t";
9876 // restore values after effect
9877 var r = this.getFxRestore();
9879 var b = this.getBox();
9880 // fixed size for slide
9884 var wrap = this.fxWrap(r.pos, o, "visible");
9886 var st = this.dom.style;
9887 st.visibility = "visible";
9888 st.position = "absolute";
9892 var after = function(){
9894 el.setDisplayed(false);
9899 el.fxUnwrap(wrap, r.pos, o);
9902 st.height = r.height;
9907 var a, zero = {to: 0};
9908 switch(anchor.toLowerCase()){
9910 st.left = st.bottom = "0";
9914 st.right = st.top = "0";
9918 st.left = st.top = "0";
9919 a = {width: zero, points: {to:[b.right, b.y]}};
9922 st.left = st.top = "0";
9923 a = {height: zero, points: {to:[b.x, b.bottom]}};
9926 st.right = st.bottom = "0";
9927 a = {width: zero, height: zero};
9930 st.right = st.top = "0";
9931 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9934 st.left = st.top = "0";
9935 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9938 st.left = st.bottom = "0";
9939 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9943 arguments.callee.anim = wrap.fxanim(a,
9953 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9954 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9955 * The element must be removed from the DOM using the 'remove' config option if desired.
9961 // common config options shown with default values
9969 * @param {Object} options (optional) Object literal with any of the Fx config options
9970 * @return {Roo.Element} The Element
9973 var el = this.getFxEl();
9976 el.queueFx(o, function(){
9977 this.clearOpacity();
9980 // restore values after effect
9981 var r = this.getFxRestore();
9982 var st = this.dom.style;
9984 var after = function(){
9986 el.setDisplayed(false);
9993 el.setPositioning(r.pos);
9995 st.height = r.height;
10000 var width = this.getWidth();
10001 var height = this.getHeight();
10003 arguments.callee.anim = this.fxanim({
10004 width : {to: this.adjustWidth(width * 2)},
10005 height : {to: this.adjustHeight(height * 2)},
10006 points : {by: [-(width * .5), -(height * .5)]},
10008 fontSize: {to:200, unit: "%"}
10019 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10020 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10021 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10027 // all config options shown with default values
10035 * @param {Object} options (optional) Object literal with any of the Fx config options
10036 * @return {Roo.Element} The Element
10038 switchOff : function(o){
10039 var el = this.getFxEl();
10042 el.queueFx(o, function(){
10043 this.clearOpacity();
10046 // restore values after effect
10047 var r = this.getFxRestore();
10048 var st = this.dom.style;
10050 var after = function(){
10052 el.setDisplayed(false);
10058 el.setPositioning(r.pos);
10059 st.width = r.width;
10060 st.height = r.height;
10065 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10066 this.clearOpacity();
10070 points:{by:[0, this.getHeight() * .5]}
10071 }, o, 'motion', 0.3, 'easeIn', after);
10072 }).defer(100, this);
10079 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10080 * changed using the "attr" config option) and then fading back to the original color. If no original
10081 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10084 // default: highlight background to yellow
10087 // custom: highlight foreground text to blue for 2 seconds
10088 el.highlight("0000ff", { attr: 'color', duration: 2 });
10090 // common config options shown with default values
10091 el.highlight("ffff9c", {
10092 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10093 endColor: (current color) or "ffffff",
10098 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10099 * @param {Object} options (optional) Object literal with any of the Fx config options
10100 * @return {Roo.Element} The Element
10102 highlight : function(color, o){
10103 var el = this.getFxEl();
10106 el.queueFx(o, function(){
10107 color = color || "ffff9c";
10108 attr = o.attr || "backgroundColor";
10110 this.clearOpacity();
10113 var origColor = this.getColor(attr);
10114 var restoreColor = this.dom.style[attr];
10115 endColor = (o.endColor || origColor) || "ffffff";
10117 var after = function(){
10118 el.dom.style[attr] = restoreColor;
10123 a[attr] = {from: color, to: endColor};
10124 arguments.callee.anim = this.fxanim(a,
10134 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10137 // default: a single light blue ripple
10140 // custom: 3 red ripples lasting 3 seconds total
10141 el.frame("ff0000", 3, { duration: 3 });
10143 // common config options shown with default values
10144 el.frame("C3DAF9", 1, {
10145 duration: 1 //duration of entire animation (not each individual ripple)
10146 // Note: Easing is not configurable and will be ignored if included
10149 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10150 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10151 * @param {Object} options (optional) Object literal with any of the Fx config options
10152 * @return {Roo.Element} The Element
10154 frame : function(color, count, o){
10155 var el = this.getFxEl();
10158 el.queueFx(o, function(){
10159 color = color || "#C3DAF9";
10160 if(color.length == 6){
10161 color = "#" + color;
10163 count = count || 1;
10164 duration = o.duration || 1;
10167 var b = this.getBox();
10168 var animFn = function(){
10169 var proxy = this.createProxy({
10172 visbility:"hidden",
10173 position:"absolute",
10174 "z-index":"35000", // yee haw
10175 border:"0px solid " + color
10178 var scale = Roo.isBorderBox ? 2 : 1;
10180 top:{from:b.y, to:b.y - 20},
10181 left:{from:b.x, to:b.x - 20},
10182 borderWidth:{from:0, to:10},
10183 opacity:{from:1, to:0},
10184 height:{from:b.height, to:(b.height + (20*scale))},
10185 width:{from:b.width, to:(b.width + (20*scale))}
10186 }, duration, function(){
10190 animFn.defer((duration/2)*1000, this);
10201 * Creates a pause before any subsequent queued effects begin. If there are
10202 * no effects queued after the pause it will have no effect.
10207 * @param {Number} seconds The length of time to pause (in seconds)
10208 * @return {Roo.Element} The Element
10210 pause : function(seconds){
10211 var el = this.getFxEl();
10214 el.queueFx(o, function(){
10215 setTimeout(function(){
10217 }, seconds * 1000);
10223 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10224 * using the "endOpacity" config option.
10227 // default: fade in from opacity 0 to 100%
10230 // custom: fade in from opacity 0 to 75% over 2 seconds
10231 el.fadeIn({ endOpacity: .75, duration: 2});
10233 // common config options shown with default values
10235 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10240 * @param {Object} options (optional) Object literal with any of the Fx config options
10241 * @return {Roo.Element} The Element
10243 fadeIn : function(o){
10244 var el = this.getFxEl();
10246 el.queueFx(o, function(){
10247 this.setOpacity(0);
10249 this.dom.style.visibility = 'visible';
10250 var to = o.endOpacity || 1;
10251 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10252 o, null, .5, "easeOut", function(){
10254 this.clearOpacity();
10263 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10264 * using the "endOpacity" config option.
10267 // default: fade out from the element's current opacity to 0
10270 // custom: fade out from the element's current opacity to 25% over 2 seconds
10271 el.fadeOut({ endOpacity: .25, duration: 2});
10273 // common config options shown with default values
10275 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10282 * @param {Object} options (optional) Object literal with any of the Fx config options
10283 * @return {Roo.Element} The Element
10285 fadeOut : function(o){
10286 var el = this.getFxEl();
10288 el.queueFx(o, function(){
10289 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10290 o, null, .5, "easeOut", function(){
10291 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10292 this.dom.style.display = "none";
10294 this.dom.style.visibility = "hidden";
10296 this.clearOpacity();
10304 * Animates the transition of an element's dimensions from a starting height/width
10305 * to an ending height/width.
10308 // change height and width to 100x100 pixels
10309 el.scale(100, 100);
10311 // common config options shown with default values. The height and width will default to
10312 // the element's existing values if passed as null.
10315 [element's height], {
10320 * @param {Number} width The new width (pass undefined to keep the original width)
10321 * @param {Number} height The new height (pass undefined to keep the original height)
10322 * @param {Object} options (optional) Object literal with any of the Fx config options
10323 * @return {Roo.Element} The Element
10325 scale : function(w, h, o){
10326 this.shift(Roo.apply({}, o, {
10334 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10335 * Any of these properties not specified in the config object will not be changed. This effect
10336 * requires that at least one new dimension, position or opacity setting must be passed in on
10337 * the config object in order for the function to have any effect.
10340 // slide the element horizontally to x position 200 while changing the height and opacity
10341 el.shift({ x: 200, height: 50, opacity: .8 });
10343 // common config options shown with default values.
10345 width: [element's width],
10346 height: [element's height],
10347 x: [element's x position],
10348 y: [element's y position],
10349 opacity: [element's opacity],
10354 * @param {Object} options Object literal with any of the Fx config options
10355 * @return {Roo.Element} The Element
10357 shift : function(o){
10358 var el = this.getFxEl();
10360 el.queueFx(o, function(){
10361 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10362 if(w !== undefined){
10363 a.width = {to: this.adjustWidth(w)};
10365 if(h !== undefined){
10366 a.height = {to: this.adjustHeight(h)};
10368 if(x !== undefined || y !== undefined){
10370 x !== undefined ? x : this.getX(),
10371 y !== undefined ? y : this.getY()
10374 if(op !== undefined){
10375 a.opacity = {to: op};
10377 if(o.xy !== undefined){
10378 a.points = {to: o.xy};
10380 arguments.callee.anim = this.fxanim(a,
10381 o, 'motion', .35, "easeOut", function(){
10389 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10390 * ending point of the effect.
10393 // default: slide the element downward while fading out
10396 // custom: slide the element out to the right with a 2-second duration
10397 el.ghost('r', { duration: 2 });
10399 // common config options shown with default values
10407 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10408 * @param {Object} options (optional) Object literal with any of the Fx config options
10409 * @return {Roo.Element} The Element
10411 ghost : function(anchor, o){
10412 var el = this.getFxEl();
10415 el.queueFx(o, function(){
10416 anchor = anchor || "b";
10418 // restore values after effect
10419 var r = this.getFxRestore();
10420 var w = this.getWidth(),
10421 h = this.getHeight();
10423 var st = this.dom.style;
10425 var after = function(){
10427 el.setDisplayed(false);
10433 el.setPositioning(r.pos);
10434 st.width = r.width;
10435 st.height = r.height;
10440 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10441 switch(anchor.toLowerCase()){
10468 arguments.callee.anim = this.fxanim(a,
10478 * Ensures that all effects queued after syncFx is called on the element are
10479 * run concurrently. This is the opposite of {@link #sequenceFx}.
10480 * @return {Roo.Element} The Element
10482 syncFx : function(){
10483 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10492 * Ensures that all effects queued after sequenceFx is called on the element are
10493 * run in sequence. This is the opposite of {@link #syncFx}.
10494 * @return {Roo.Element} The Element
10496 sequenceFx : function(){
10497 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10499 concurrent : false,
10506 nextFx : function(){
10507 var ef = this.fxQueue[0];
10514 * Returns true if the element has any effects actively running or queued, else returns false.
10515 * @return {Boolean} True if element has active effects, else false
10517 hasActiveFx : function(){
10518 return this.fxQueue && this.fxQueue[0];
10522 * Stops any running effects and clears the element's internal effects queue if it contains
10523 * any additional effects that haven't started yet.
10524 * @return {Roo.Element} The Element
10526 stopFx : function(){
10527 if(this.hasActiveFx()){
10528 var cur = this.fxQueue[0];
10529 if(cur && cur.anim && cur.anim.isAnimated()){
10530 this.fxQueue = [cur]; // clear out others
10531 cur.anim.stop(true);
10538 beforeFx : function(o){
10539 if(this.hasActiveFx() && !o.concurrent){
10550 * Returns true if the element is currently blocking so that no other effect can be queued
10551 * until this effect is finished, else returns false if blocking is not set. This is commonly
10552 * used to ensure that an effect initiated by a user action runs to completion prior to the
10553 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10554 * @return {Boolean} True if blocking, else false
10556 hasFxBlock : function(){
10557 var q = this.fxQueue;
10558 return q && q[0] && q[0].block;
10562 queueFx : function(o, fn){
10566 if(!this.hasFxBlock()){
10567 Roo.applyIf(o, this.fxDefaults);
10569 var run = this.beforeFx(o);
10570 fn.block = o.block;
10571 this.fxQueue.push(fn);
10583 fxWrap : function(pos, o, vis){
10585 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10588 wrapXY = this.getXY();
10590 var div = document.createElement("div");
10591 div.style.visibility = vis;
10592 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10593 wrap.setPositioning(pos);
10594 if(wrap.getStyle("position") == "static"){
10595 wrap.position("relative");
10597 this.clearPositioning('auto');
10599 wrap.dom.appendChild(this.dom);
10601 wrap.setXY(wrapXY);
10608 fxUnwrap : function(wrap, pos, o){
10609 this.clearPositioning();
10610 this.setPositioning(pos);
10612 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10618 getFxRestore : function(){
10619 var st = this.dom.style;
10620 return {pos: this.getPositioning(), width: st.width, height : st.height};
10624 afterFx : function(o){
10626 this.applyStyles(o.afterStyle);
10629 this.addClass(o.afterCls);
10631 if(o.remove === true){
10634 Roo.callback(o.callback, o.scope, [this]);
10636 this.fxQueue.shift();
10642 getFxEl : function(){ // support for composite element fx
10643 return Roo.get(this.dom);
10647 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10648 animType = animType || 'run';
10650 var anim = Roo.lib.Anim[animType](
10652 (opt.duration || defaultDur) || .35,
10653 (opt.easing || defaultEase) || 'easeOut',
10655 Roo.callback(cb, this);
10664 // backwords compat
10665 Roo.Fx.resize = Roo.Fx.scale;
10667 //When included, Roo.Fx is automatically applied to Element so that all basic
10668 //effects are available directly via the Element API
10669 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10671 * Ext JS Library 1.1.1
10672 * Copyright(c) 2006-2007, Ext JS, LLC.
10674 * Originally Released Under LGPL - original licence link has changed is not relivant.
10677 * <script type="text/javascript">
10682 * @class Roo.CompositeElement
10683 * Standard composite class. Creates a Roo.Element for every element in the collection.
10685 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10686 * actions will be performed on all the elements in this collection.</b>
10688 * All methods return <i>this</i> and can be chained.
10690 var els = Roo.select("#some-el div.some-class", true);
10691 // or select directly from an existing element
10692 var el = Roo.get('some-el');
10693 el.select('div.some-class', true);
10695 els.setWidth(100); // all elements become 100 width
10696 els.hide(true); // all elements fade out and hide
10698 els.setWidth(100).hide(true);
10701 Roo.CompositeElement = function(els){
10702 this.elements = [];
10703 this.addElements(els);
10705 Roo.CompositeElement.prototype = {
10707 addElements : function(els){
10708 if(!els) return this;
10709 if(typeof els == "string"){
10710 els = Roo.Element.selectorFunction(els);
10712 var yels = this.elements;
10713 var index = yels.length-1;
10714 for(var i = 0, len = els.length; i < len; i++) {
10715 yels[++index] = Roo.get(els[i]);
10721 * Clears this composite and adds the elements returned by the passed selector.
10722 * @param {String/Array} els A string CSS selector, an array of elements or an element
10723 * @return {CompositeElement} this
10725 fill : function(els){
10726 this.elements = [];
10732 * Filters this composite to only elements that match the passed selector.
10733 * @param {String} selector A string CSS selector
10734 * @return {CompositeElement} this
10736 filter : function(selector){
10738 this.each(function(el){
10739 if(el.is(selector)){
10740 els[els.length] = el.dom;
10747 invoke : function(fn, args){
10748 var els = this.elements;
10749 for(var i = 0, len = els.length; i < len; i++) {
10750 Roo.Element.prototype[fn].apply(els[i], args);
10755 * Adds elements to this composite.
10756 * @param {String/Array} els A string CSS selector, an array of elements or an element
10757 * @return {CompositeElement} this
10759 add : function(els){
10760 if(typeof els == "string"){
10761 this.addElements(Roo.Element.selectorFunction(els));
10762 }else if(els.length !== undefined){
10763 this.addElements(els);
10765 this.addElements([els]);
10770 * Calls the passed function passing (el, this, index) for each element in this composite.
10771 * @param {Function} fn The function to call
10772 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10773 * @return {CompositeElement} this
10775 each : function(fn, scope){
10776 var els = this.elements;
10777 for(var i = 0, len = els.length; i < len; i++){
10778 if(fn.call(scope || els[i], els[i], this, i) === false) {
10786 * Returns the Element object at the specified index
10787 * @param {Number} index
10788 * @return {Roo.Element}
10790 item : function(index){
10791 return this.elements[index] || null;
10795 * Returns the first Element
10796 * @return {Roo.Element}
10798 first : function(){
10799 return this.item(0);
10803 * Returns the last Element
10804 * @return {Roo.Element}
10807 return this.item(this.elements.length-1);
10811 * Returns the number of elements in this composite
10814 getCount : function(){
10815 return this.elements.length;
10819 * Returns true if this composite contains the passed element
10822 contains : function(el){
10823 return this.indexOf(el) !== -1;
10827 * Returns true if this composite contains the passed element
10830 indexOf : function(el){
10831 return this.elements.indexOf(Roo.get(el));
10836 * Removes the specified element(s).
10837 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10838 * or an array of any of those.
10839 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10840 * @return {CompositeElement} this
10842 removeElement : function(el, removeDom){
10843 if(el instanceof Array){
10844 for(var i = 0, len = el.length; i < len; i++){
10845 this.removeElement(el[i]);
10849 var index = typeof el == 'number' ? el : this.indexOf(el);
10852 var d = this.elements[index];
10856 d.parentNode.removeChild(d);
10859 this.elements.splice(index, 1);
10865 * Replaces the specified element with the passed element.
10866 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10868 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10869 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10870 * @return {CompositeElement} this
10872 replaceElement : function(el, replacement, domReplace){
10873 var index = typeof el == 'number' ? el : this.indexOf(el);
10876 this.elements[index].replaceWith(replacement);
10878 this.elements.splice(index, 1, Roo.get(replacement))
10885 * Removes all elements.
10887 clear : function(){
10888 this.elements = [];
10892 Roo.CompositeElement.createCall = function(proto, fnName){
10893 if(!proto[fnName]){
10894 proto[fnName] = function(){
10895 return this.invoke(fnName, arguments);
10899 for(var fnName in Roo.Element.prototype){
10900 if(typeof Roo.Element.prototype[fnName] == "function"){
10901 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10907 * Ext JS Library 1.1.1
10908 * Copyright(c) 2006-2007, Ext JS, LLC.
10910 * Originally Released Under LGPL - original licence link has changed is not relivant.
10913 * <script type="text/javascript">
10917 * @class Roo.CompositeElementLite
10918 * @extends Roo.CompositeElement
10919 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10921 var els = Roo.select("#some-el div.some-class");
10922 // or select directly from an existing element
10923 var el = Roo.get('some-el');
10924 el.select('div.some-class');
10926 els.setWidth(100); // all elements become 100 width
10927 els.hide(true); // all elements fade out and hide
10929 els.setWidth(100).hide(true);
10930 </code></pre><br><br>
10931 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10932 * actions will be performed on all the elements in this collection.</b>
10934 Roo.CompositeElementLite = function(els){
10935 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10936 this.el = new Roo.Element.Flyweight();
10938 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10939 addElements : function(els){
10941 if(els instanceof Array){
10942 this.elements = this.elements.concat(els);
10944 var yels = this.elements;
10945 var index = yels.length-1;
10946 for(var i = 0, len = els.length; i < len; i++) {
10947 yels[++index] = els[i];
10953 invoke : function(fn, args){
10954 var els = this.elements;
10956 for(var i = 0, len = els.length; i < len; i++) {
10958 Roo.Element.prototype[fn].apply(el, args);
10963 * Returns a flyweight Element of the dom element object at the specified index
10964 * @param {Number} index
10965 * @return {Roo.Element}
10967 item : function(index){
10968 if(!this.elements[index]){
10971 this.el.dom = this.elements[index];
10975 // fixes scope with flyweight
10976 addListener : function(eventName, handler, scope, opt){
10977 var els = this.elements;
10978 for(var i = 0, len = els.length; i < len; i++) {
10979 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10985 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10986 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10987 * a reference to the dom node, use el.dom.</b>
10988 * @param {Function} fn The function to call
10989 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10990 * @return {CompositeElement} this
10992 each : function(fn, scope){
10993 var els = this.elements;
10995 for(var i = 0, len = els.length; i < len; i++){
10997 if(fn.call(scope || el, el, this, i) === false){
11004 indexOf : function(el){
11005 return this.elements.indexOf(Roo.getDom(el));
11008 replaceElement : function(el, replacement, domReplace){
11009 var index = typeof el == 'number' ? el : this.indexOf(el);
11011 replacement = Roo.getDom(replacement);
11013 var d = this.elements[index];
11014 d.parentNode.insertBefore(replacement, d);
11015 d.parentNode.removeChild(d);
11017 this.elements.splice(index, 1, replacement);
11022 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11026 * Ext JS Library 1.1.1
11027 * Copyright(c) 2006-2007, Ext JS, LLC.
11029 * Originally Released Under LGPL - original licence link has changed is not relivant.
11032 * <script type="text/javascript">
11038 * @class Roo.data.Connection
11039 * @extends Roo.util.Observable
11040 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11041 * either to a configured URL, or to a URL specified at request time.<br><br>
11043 * Requests made by this class are asynchronous, and will return immediately. No data from
11044 * the server will be available to the statement immediately following the {@link #request} call.
11045 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11047 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11048 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11049 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11050 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11051 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11052 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11053 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11054 * standard DOM methods.
11056 * @param {Object} config a configuration object.
11058 Roo.data.Connection = function(config){
11059 Roo.apply(this, config);
11062 * @event beforerequest
11063 * Fires before a network request is made to retrieve a data object.
11064 * @param {Connection} conn This Connection object.
11065 * @param {Object} options The options config object passed to the {@link #request} method.
11067 "beforerequest" : true,
11069 * @event requestcomplete
11070 * Fires if the request was successfully completed.
11071 * @param {Connection} conn This Connection object.
11072 * @param {Object} response The XHR object containing the response data.
11073 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11074 * @param {Object} options The options config object passed to the {@link #request} method.
11076 "requestcomplete" : true,
11078 * @event requestexception
11079 * Fires if an error HTTP status was returned from the server.
11080 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11081 * @param {Connection} conn This Connection object.
11082 * @param {Object} response The XHR object containing the response data.
11083 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11084 * @param {Object} options The options config object passed to the {@link #request} method.
11086 "requestexception" : true
11088 Roo.data.Connection.superclass.constructor.call(this);
11091 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11093 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11096 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11097 * extra parameters to each request made by this object. (defaults to undefined)
11100 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11101 * to each request made by this object. (defaults to undefined)
11104 * @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)
11107 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11111 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11117 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11120 disableCaching: true,
11123 * Sends an HTTP request to a remote server.
11124 * @param {Object} options An object which may contain the following properties:<ul>
11125 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11126 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11127 * request, a url encoded string or a function to call to get either.</li>
11128 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11129 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11130 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11131 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11132 * <li>options {Object} The parameter to the request call.</li>
11133 * <li>success {Boolean} True if the request succeeded.</li>
11134 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11136 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11137 * The callback is passed the following parameters:<ul>
11138 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11139 * <li>options {Object} The parameter to the request call.</li>
11141 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11142 * The callback is passed the following parameters:<ul>
11143 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11144 * <li>options {Object} The parameter to the request call.</li>
11146 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11147 * for the callback function. Defaults to the browser window.</li>
11148 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11149 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11150 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11151 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11152 * params for the post data. Any params will be appended to the URL.</li>
11153 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11155 * @return {Number} transactionId
11157 request : function(o){
11158 if(this.fireEvent("beforerequest", this, o) !== false){
11161 if(typeof p == "function"){
11162 p = p.call(o.scope||window, o);
11164 if(typeof p == "object"){
11165 p = Roo.urlEncode(o.params);
11167 if(this.extraParams){
11168 var extras = Roo.urlEncode(this.extraParams);
11169 p = p ? (p + '&' + extras) : extras;
11172 var url = o.url || this.url;
11173 if(typeof url == 'function'){
11174 url = url.call(o.scope||window, o);
11178 var form = Roo.getDom(o.form);
11179 url = url || form.action;
11181 var enctype = form.getAttribute("enctype");
11182 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11183 return this.doFormUpload(o, p, url);
11185 var f = Roo.lib.Ajax.serializeForm(form);
11186 p = p ? (p + '&' + f) : f;
11189 var hs = o.headers;
11190 if(this.defaultHeaders){
11191 hs = Roo.apply(hs || {}, this.defaultHeaders);
11198 success: this.handleResponse,
11199 failure: this.handleFailure,
11201 argument: {options: o},
11202 timeout : this.timeout
11205 var method = o.method||this.method||(p ? "POST" : "GET");
11207 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11208 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11211 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11215 }else if(this.autoAbort !== false){
11219 if((method == 'GET' && p) || o.xmlData){
11220 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11223 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11224 return this.transId;
11226 Roo.callback(o.callback, o.scope, [o, null, null]);
11232 * Determine whether this object has a request outstanding.
11233 * @param {Number} transactionId (Optional) defaults to the last transaction
11234 * @return {Boolean} True if there is an outstanding request.
11236 isLoading : function(transId){
11238 return Roo.lib.Ajax.isCallInProgress(transId);
11240 return this.transId ? true : false;
11245 * Aborts any outstanding request.
11246 * @param {Number} transactionId (Optional) defaults to the last transaction
11248 abort : function(transId){
11249 if(transId || this.isLoading()){
11250 Roo.lib.Ajax.abort(transId || this.transId);
11255 handleResponse : function(response){
11256 this.transId = false;
11257 var options = response.argument.options;
11258 response.argument = options ? options.argument : null;
11259 this.fireEvent("requestcomplete", this, response, options);
11260 Roo.callback(options.success, options.scope, [response, options]);
11261 Roo.callback(options.callback, options.scope, [options, true, response]);
11265 handleFailure : function(response, e){
11266 this.transId = false;
11267 var options = response.argument.options;
11268 response.argument = options ? options.argument : null;
11269 this.fireEvent("requestexception", this, response, options, e);
11270 Roo.callback(options.failure, options.scope, [response, options]);
11271 Roo.callback(options.callback, options.scope, [options, false, response]);
11275 doFormUpload : function(o, ps, url){
11277 var frame = document.createElement('iframe');
11280 frame.className = 'x-hidden';
11282 frame.src = Roo.SSL_SECURE_URL;
11284 document.body.appendChild(frame);
11287 document.frames[id].name = id;
11290 var form = Roo.getDom(o.form);
11292 form.method = 'POST';
11293 form.enctype = form.encoding = 'multipart/form-data';
11299 if(ps){ // add dynamic params
11301 ps = Roo.urlDecode(ps, false);
11303 if(ps.hasOwnProperty(k)){
11304 hd = document.createElement('input');
11305 hd.type = 'hidden';
11308 form.appendChild(hd);
11315 var r = { // bogus response object
11320 r.argument = o ? o.argument : null;
11325 doc = frame.contentWindow.document;
11327 doc = (frame.contentDocument || window.frames[id].document);
11329 if(doc && doc.body){
11330 r.responseText = doc.body.innerHTML;
11332 if(doc && doc.XMLDocument){
11333 r.responseXML = doc.XMLDocument;
11335 r.responseXML = doc;
11342 Roo.EventManager.removeListener(frame, 'load', cb, this);
11344 this.fireEvent("requestcomplete", this, r, o);
11345 Roo.callback(o.success, o.scope, [r, o]);
11346 Roo.callback(o.callback, o.scope, [o, true, r]);
11348 setTimeout(function(){document.body.removeChild(frame);}, 100);
11351 Roo.EventManager.on(frame, 'load', cb, this);
11354 if(hiddens){ // remove dynamic params
11355 for(var i = 0, len = hiddens.length; i < len; i++){
11356 form.removeChild(hiddens[i]);
11364 * @extends Roo.data.Connection
11365 * Global Ajax request class.
11369 Roo.Ajax = new Roo.data.Connection({
11372 * @cfg {String} url @hide
11375 * @cfg {Object} extraParams @hide
11378 * @cfg {Object} defaultHeaders @hide
11381 * @cfg {String} method (Optional) @hide
11384 * @cfg {Number} timeout (Optional) @hide
11387 * @cfg {Boolean} autoAbort (Optional) @hide
11391 * @cfg {Boolean} disableCaching (Optional) @hide
11395 * @property disableCaching
11396 * True to add a unique cache-buster param to GET requests. (defaults to true)
11401 * The default URL to be used for requests to the server. (defaults to undefined)
11405 * @property extraParams
11406 * An object containing properties which are used as
11407 * extra parameters to each request made by this object. (defaults to undefined)
11411 * @property defaultHeaders
11412 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11417 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11421 * @property timeout
11422 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11427 * @property autoAbort
11428 * Whether a new request should abort any pending requests. (defaults to false)
11434 * Serialize the passed form into a url encoded string
11435 * @param {String/HTMLElement} form
11438 serializeForm : function(form){
11439 return Roo.lib.Ajax.serializeForm(form);
11443 * Ext JS Library 1.1.1
11444 * Copyright(c) 2006-2007, Ext JS, LLC.
11446 * Originally Released Under LGPL - original licence link has changed is not relivant.
11449 * <script type="text/javascript">
11454 * @extends Roo.data.Connection
11455 * Global Ajax request class.
11457 * @instanceOf Roo.data.Connection
11459 Roo.Ajax = new Roo.data.Connection({
11468 * @cfg {String} url @hide
11471 * @cfg {Object} extraParams @hide
11474 * @cfg {Object} defaultHeaders @hide
11477 * @cfg {String} method (Optional) @hide
11480 * @cfg {Number} timeout (Optional) @hide
11483 * @cfg {Boolean} autoAbort (Optional) @hide
11487 * @cfg {Boolean} disableCaching (Optional) @hide
11491 * @property disableCaching
11492 * True to add a unique cache-buster param to GET requests. (defaults to true)
11497 * The default URL to be used for requests to the server. (defaults to undefined)
11501 * @property extraParams
11502 * An object containing properties which are used as
11503 * extra parameters to each request made by this object. (defaults to undefined)
11507 * @property defaultHeaders
11508 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11513 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11517 * @property timeout
11518 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11523 * @property autoAbort
11524 * Whether a new request should abort any pending requests. (defaults to false)
11530 * Serialize the passed form into a url encoded string
11531 * @param {String/HTMLElement} form
11534 serializeForm : function(form){
11535 return Roo.lib.Ajax.serializeForm(form);
11539 * Ext JS Library 1.1.1
11540 * Copyright(c) 2006-2007, Ext JS, LLC.
11542 * Originally Released Under LGPL - original licence link has changed is not relivant.
11545 * <script type="text/javascript">
11550 * @class Roo.UpdateManager
11551 * @extends Roo.util.Observable
11552 * Provides AJAX-style update for Element object.<br><br>
11555 * // Get it from a Roo.Element object
11556 * var el = Roo.get("foo");
11557 * var mgr = el.getUpdateManager();
11558 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11560 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11562 * // or directly (returns the same UpdateManager instance)
11563 * var mgr = new Roo.UpdateManager("myElementId");
11564 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11565 * mgr.on("update", myFcnNeedsToKnow);
11567 // short handed call directly from the element object
11568 Roo.get("foo").load({
11572 text: "Loading Foo..."
11576 * Create new UpdateManager directly.
11577 * @param {String/HTMLElement/Roo.Element} el The element to update
11578 * @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).
11580 Roo.UpdateManager = function(el, forceNew){
11582 if(!forceNew && el.updateManager){
11583 return el.updateManager;
11586 * The Element object
11587 * @type Roo.Element
11591 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11594 this.defaultUrl = null;
11598 * @event beforeupdate
11599 * Fired before an update is made, return false from your handler and the update is cancelled.
11600 * @param {Roo.Element} el
11601 * @param {String/Object/Function} url
11602 * @param {String/Object} params
11604 "beforeupdate": true,
11607 * Fired after successful update is made.
11608 * @param {Roo.Element} el
11609 * @param {Object} oResponseObject The response Object
11614 * Fired on update failure.
11615 * @param {Roo.Element} el
11616 * @param {Object} oResponseObject The response Object
11620 var d = Roo.UpdateManager.defaults;
11622 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11625 this.sslBlankUrl = d.sslBlankUrl;
11627 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11630 this.disableCaching = d.disableCaching;
11632 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11635 this.indicatorText = d.indicatorText;
11637 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11640 this.showLoadIndicator = d.showLoadIndicator;
11642 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11645 this.timeout = d.timeout;
11648 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11651 this.loadScripts = d.loadScripts;
11654 * Transaction object of current executing transaction
11656 this.transaction = null;
11661 this.autoRefreshProcId = null;
11663 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11666 this.refreshDelegate = this.refresh.createDelegate(this);
11668 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11671 this.updateDelegate = this.update.createDelegate(this);
11673 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11676 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11680 this.successDelegate = this.processSuccess.createDelegate(this);
11684 this.failureDelegate = this.processFailure.createDelegate(this);
11686 if(!this.renderer){
11688 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11690 this.renderer = new Roo.UpdateManager.BasicRenderer();
11693 Roo.UpdateManager.superclass.constructor.call(this);
11696 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11698 * Get the Element this UpdateManager is bound to
11699 * @return {Roo.Element} The element
11701 getEl : function(){
11705 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11706 * @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:
11709 url: "your-url.php",<br/>
11710 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11711 callback: yourFunction,<br/>
11712 scope: yourObject, //(optional scope) <br/>
11713 discardUrl: false, <br/>
11714 nocache: false,<br/>
11715 text: "Loading...",<br/>
11717 scripts: false<br/>
11720 * The only required property is url. The optional properties nocache, text and scripts
11721 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11722 * @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}
11723 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11724 * @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.
11726 update : function(url, params, callback, discardUrl){
11727 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11728 var method = this.method, cfg;
11729 if(typeof url == "object"){ // must be config object
11732 params = params || cfg.params;
11733 callback = callback || cfg.callback;
11734 discardUrl = discardUrl || cfg.discardUrl;
11735 if(callback && cfg.scope){
11736 callback = callback.createDelegate(cfg.scope);
11738 if(typeof cfg.method != "undefined"){method = cfg.method;};
11739 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11740 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11741 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11742 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11744 this.showLoading();
11746 this.defaultUrl = url;
11748 if(typeof url == "function"){
11749 url = url.call(this);
11752 method = method || (params ? "POST" : "GET");
11753 if(method == "GET"){
11754 url = this.prepareUrl(url);
11757 var o = Roo.apply(cfg ||{}, {
11760 success: this.successDelegate,
11761 failure: this.failureDelegate,
11762 callback: undefined,
11763 timeout: (this.timeout*1000),
11764 argument: {"url": url, "form": null, "callback": callback, "params": params}
11767 this.transaction = Roo.Ajax.request(o);
11772 * 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.
11773 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11774 * @param {String/HTMLElement} form The form Id or form element
11775 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11776 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11777 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11779 formUpdate : function(form, url, reset, callback){
11780 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11781 if(typeof url == "function"){
11782 url = url.call(this);
11784 form = Roo.getDom(form);
11785 this.transaction = Roo.Ajax.request({
11788 success: this.successDelegate,
11789 failure: this.failureDelegate,
11790 timeout: (this.timeout*1000),
11791 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11793 this.showLoading.defer(1, this);
11798 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11799 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11801 refresh : function(callback){
11802 if(this.defaultUrl == null){
11805 this.update(this.defaultUrl, null, callback, true);
11809 * Set this element to auto refresh.
11810 * @param {Number} interval How often to update (in seconds).
11811 * @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)
11812 * @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}
11813 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11814 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11816 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11818 this.update(url || this.defaultUrl, params, callback, true);
11820 if(this.autoRefreshProcId){
11821 clearInterval(this.autoRefreshProcId);
11823 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11827 * Stop auto refresh on this element.
11829 stopAutoRefresh : function(){
11830 if(this.autoRefreshProcId){
11831 clearInterval(this.autoRefreshProcId);
11832 delete this.autoRefreshProcId;
11836 isAutoRefreshing : function(){
11837 return this.autoRefreshProcId ? true : false;
11840 * Called to update the element to "Loading" state. Override to perform custom action.
11842 showLoading : function(){
11843 if(this.showLoadIndicator){
11844 this.el.update(this.indicatorText);
11849 * Adds unique parameter to query string if disableCaching = true
11852 prepareUrl : function(url){
11853 if(this.disableCaching){
11854 var append = "_dc=" + (new Date().getTime());
11855 if(url.indexOf("?") !== -1){
11856 url += "&" + append;
11858 url += "?" + append;
11867 processSuccess : function(response){
11868 this.transaction = null;
11869 if(response.argument.form && response.argument.reset){
11870 try{ // put in try/catch since some older FF releases had problems with this
11871 response.argument.form.reset();
11874 if(this.loadScripts){
11875 this.renderer.render(this.el, response, this,
11876 this.updateComplete.createDelegate(this, [response]));
11878 this.renderer.render(this.el, response, this);
11879 this.updateComplete(response);
11883 updateComplete : function(response){
11884 this.fireEvent("update", this.el, response);
11885 if(typeof response.argument.callback == "function"){
11886 response.argument.callback(this.el, true, response);
11893 processFailure : function(response){
11894 this.transaction = null;
11895 this.fireEvent("failure", this.el, response);
11896 if(typeof response.argument.callback == "function"){
11897 response.argument.callback(this.el, false, response);
11902 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11903 * @param {Object} renderer The object implementing the render() method
11905 setRenderer : function(renderer){
11906 this.renderer = renderer;
11909 getRenderer : function(){
11910 return this.renderer;
11914 * Set the defaultUrl used for updates
11915 * @param {String/Function} defaultUrl The url or a function to call to get the url
11917 setDefaultUrl : function(defaultUrl){
11918 this.defaultUrl = defaultUrl;
11922 * Aborts the executing transaction
11924 abort : function(){
11925 if(this.transaction){
11926 Roo.Ajax.abort(this.transaction);
11931 * Returns true if an update is in progress
11932 * @return {Boolean}
11934 isUpdating : function(){
11935 if(this.transaction){
11936 return Roo.Ajax.isLoading(this.transaction);
11943 * @class Roo.UpdateManager.defaults
11944 * @static (not really - but it helps the doc tool)
11945 * The defaults collection enables customizing the default properties of UpdateManager
11947 Roo.UpdateManager.defaults = {
11949 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11955 * True to process scripts by default (Defaults to false).
11958 loadScripts : false,
11961 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11964 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11966 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11969 disableCaching : false,
11971 * Whether to show indicatorText when loading (Defaults to true).
11974 showLoadIndicator : true,
11976 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11979 indicatorText : '<div class="loading-indicator">Loading...</div>'
11983 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11985 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11986 * @param {String/HTMLElement/Roo.Element} el The element to update
11987 * @param {String} url The url
11988 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11989 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11992 * @member Roo.UpdateManager
11994 Roo.UpdateManager.updateElement = function(el, url, params, options){
11995 var um = Roo.get(el, true).getUpdateManager();
11996 Roo.apply(um, options);
11997 um.update(url, params, options ? options.callback : null);
11999 // alias for backwards compat
12000 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12002 * @class Roo.UpdateManager.BasicRenderer
12003 * Default Content renderer. Updates the elements innerHTML with the responseText.
12005 Roo.UpdateManager.BasicRenderer = function(){};
12007 Roo.UpdateManager.BasicRenderer.prototype = {
12009 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12010 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12011 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12012 * @param {Roo.Element} el The element being rendered
12013 * @param {Object} response The YUI Connect response object
12014 * @param {UpdateManager} updateManager The calling update manager
12015 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12017 render : function(el, response, updateManager, callback){
12018 el.update(response.responseText, updateManager.loadScripts, callback);
12023 * Ext JS Library 1.1.1
12024 * Copyright(c) 2006-2007, Ext JS, LLC.
12026 * Originally Released Under LGPL - original licence link has changed is not relivant.
12029 * <script type="text/javascript">
12033 * @class Roo.util.DelayedTask
12034 * Provides a convenient method of performing setTimeout where a new
12035 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12036 * You can use this class to buffer
12037 * the keypress events for a certain number of milliseconds, and perform only if they stop
12038 * for that amount of time.
12039 * @constructor The parameters to this constructor serve as defaults and are not required.
12040 * @param {Function} fn (optional) The default function to timeout
12041 * @param {Object} scope (optional) The default scope of that timeout
12042 * @param {Array} args (optional) The default Array of arguments
12044 Roo.util.DelayedTask = function(fn, scope, args){
12045 var id = null, d, t;
12047 var call = function(){
12048 var now = new Date().getTime();
12052 fn.apply(scope, args || []);
12056 * Cancels any pending timeout and queues a new one
12057 * @param {Number} delay The milliseconds to delay
12058 * @param {Function} newFn (optional) Overrides function passed to constructor
12059 * @param {Object} newScope (optional) Overrides scope passed to constructor
12060 * @param {Array} newArgs (optional) Overrides args passed to constructor
12062 this.delay = function(delay, newFn, newScope, newArgs){
12063 if(id && delay != d){
12067 t = new Date().getTime();
12069 scope = newScope || scope;
12070 args = newArgs || args;
12072 id = setInterval(call, d);
12077 * Cancel the last queued timeout
12079 this.cancel = function(){
12087 * Ext JS Library 1.1.1
12088 * Copyright(c) 2006-2007, Ext JS, LLC.
12090 * Originally Released Under LGPL - original licence link has changed is not relivant.
12093 * <script type="text/javascript">
12097 Roo.util.TaskRunner = function(interval){
12098 interval = interval || 10;
12099 var tasks = [], removeQueue = [];
12101 var running = false;
12103 var stopThread = function(){
12109 var startThread = function(){
12112 id = setInterval(runTasks, interval);
12116 var removeTask = function(task){
12117 removeQueue.push(task);
12123 var runTasks = function(){
12124 if(removeQueue.length > 0){
12125 for(var i = 0, len = removeQueue.length; i < len; i++){
12126 tasks.remove(removeQueue[i]);
12129 if(tasks.length < 1){
12134 var now = new Date().getTime();
12135 for(var i = 0, len = tasks.length; i < len; ++i){
12137 var itime = now - t.taskRunTime;
12138 if(t.interval <= itime){
12139 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12140 t.taskRunTime = now;
12141 if(rt === false || t.taskRunCount === t.repeat){
12146 if(t.duration && t.duration <= (now - t.taskStartTime)){
12153 * Queues a new task.
12154 * @param {Object} task
12156 this.start = function(task){
12158 task.taskStartTime = new Date().getTime();
12159 task.taskRunTime = 0;
12160 task.taskRunCount = 0;
12165 this.stop = function(task){
12170 this.stopAll = function(){
12172 for(var i = 0, len = tasks.length; i < len; i++){
12173 if(tasks[i].onStop){
12182 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12184 * Ext JS Library 1.1.1
12185 * Copyright(c) 2006-2007, Ext JS, LLC.
12187 * Originally Released Under LGPL - original licence link has changed is not relivant.
12190 * <script type="text/javascript">
12195 * @class Roo.util.MixedCollection
12196 * @extends Roo.util.Observable
12197 * A Collection class that maintains both numeric indexes and keys and exposes events.
12199 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12200 * collection (defaults to false)
12201 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12202 * and return the key value for that item. This is used when available to look up the key on items that
12203 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12204 * equivalent to providing an implementation for the {@link #getKey} method.
12206 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12214 * Fires when the collection is cleared.
12219 * Fires when an item is added to the collection.
12220 * @param {Number} index The index at which the item was added.
12221 * @param {Object} o The item added.
12222 * @param {String} key The key associated with the added item.
12227 * Fires when an item is replaced in the collection.
12228 * @param {String} key he key associated with the new added.
12229 * @param {Object} old The item being replaced.
12230 * @param {Object} new The new item.
12235 * Fires when an item is removed from the collection.
12236 * @param {Object} o The item being removed.
12237 * @param {String} key (optional) The key associated with the removed item.
12242 this.allowFunctions = allowFunctions === true;
12244 this.getKey = keyFn;
12246 Roo.util.MixedCollection.superclass.constructor.call(this);
12249 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12250 allowFunctions : false,
12253 * Adds an item to the collection.
12254 * @param {String} key The key to associate with the item
12255 * @param {Object} o The item to add.
12256 * @return {Object} The item added.
12258 add : function(key, o){
12259 if(arguments.length == 1){
12261 key = this.getKey(o);
12263 if(typeof key == "undefined" || key === null){
12265 this.items.push(o);
12266 this.keys.push(null);
12268 var old = this.map[key];
12270 return this.replace(key, o);
12273 this.items.push(o);
12275 this.keys.push(key);
12277 this.fireEvent("add", this.length-1, o, key);
12282 * MixedCollection has a generic way to fetch keys if you implement getKey.
12285 var mc = new Roo.util.MixedCollection();
12286 mc.add(someEl.dom.id, someEl);
12287 mc.add(otherEl.dom.id, otherEl);
12291 var mc = new Roo.util.MixedCollection();
12292 mc.getKey = function(el){
12298 // or via the constructor
12299 var mc = new Roo.util.MixedCollection(false, function(el){
12305 * @param o {Object} The item for which to find the key.
12306 * @return {Object} The key for the passed item.
12308 getKey : function(o){
12313 * Replaces an item in the collection.
12314 * @param {String} key The key associated with the item to replace, or the item to replace.
12315 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12316 * @return {Object} The new item.
12318 replace : function(key, o){
12319 if(arguments.length == 1){
12321 key = this.getKey(o);
12323 var old = this.item(key);
12324 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12325 return this.add(key, o);
12327 var index = this.indexOfKey(key);
12328 this.items[index] = o;
12330 this.fireEvent("replace", key, old, o);
12335 * Adds all elements of an Array or an Object to the collection.
12336 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12337 * an Array of values, each of which are added to the collection.
12339 addAll : function(objs){
12340 if(arguments.length > 1 || objs instanceof Array){
12341 var args = arguments.length > 1 ? arguments : objs;
12342 for(var i = 0, len = args.length; i < len; i++){
12346 for(var key in objs){
12347 if(this.allowFunctions || typeof objs[key] != "function"){
12348 this.add(key, objs[key]);
12355 * Executes the specified function once for every item in the collection, passing each
12356 * item as the first and only parameter. returning false from the function will stop the iteration.
12357 * @param {Function} fn The function to execute for each item.
12358 * @param {Object} scope (optional) The scope in which to execute the function.
12360 each : function(fn, scope){
12361 var items = [].concat(this.items); // each safe for removal
12362 for(var i = 0, len = items.length; i < len; i++){
12363 if(fn.call(scope || items[i], items[i], i, len) === false){
12370 * Executes the specified function once for every key in the collection, passing each
12371 * key, and its associated item as the first two parameters.
12372 * @param {Function} fn The function to execute for each item.
12373 * @param {Object} scope (optional) The scope in which to execute the function.
12375 eachKey : function(fn, scope){
12376 for(var i = 0, len = this.keys.length; i < len; i++){
12377 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12382 * Returns the first item in the collection which elicits a true return value from the
12383 * passed selection function.
12384 * @param {Function} fn The selection function to execute for each item.
12385 * @param {Object} scope (optional) The scope in which to execute the function.
12386 * @return {Object} The first item in the collection which returned true from the selection function.
12388 find : function(fn, scope){
12389 for(var i = 0, len = this.items.length; i < len; i++){
12390 if(fn.call(scope || window, this.items[i], this.keys[i])){
12391 return this.items[i];
12398 * Inserts an item at the specified index in the collection.
12399 * @param {Number} index The index to insert the item at.
12400 * @param {String} key The key to associate with the new item, or the item itself.
12401 * @param {Object} o (optional) If the second parameter was a key, the new item.
12402 * @return {Object} The item inserted.
12404 insert : function(index, key, o){
12405 if(arguments.length == 2){
12407 key = this.getKey(o);
12409 if(index >= this.length){
12410 return this.add(key, o);
12413 this.items.splice(index, 0, o);
12414 if(typeof key != "undefined" && key != null){
12417 this.keys.splice(index, 0, key);
12418 this.fireEvent("add", index, o, key);
12423 * Removed an item from the collection.
12424 * @param {Object} o The item to remove.
12425 * @return {Object} The item removed.
12427 remove : function(o){
12428 return this.removeAt(this.indexOf(o));
12432 * Remove an item from a specified index in the collection.
12433 * @param {Number} index The index within the collection of the item to remove.
12435 removeAt : function(index){
12436 if(index < this.length && index >= 0){
12438 var o = this.items[index];
12439 this.items.splice(index, 1);
12440 var key = this.keys[index];
12441 if(typeof key != "undefined"){
12442 delete this.map[key];
12444 this.keys.splice(index, 1);
12445 this.fireEvent("remove", o, key);
12450 * Removed an item associated with the passed key fom the collection.
12451 * @param {String} key The key of the item to remove.
12453 removeKey : function(key){
12454 return this.removeAt(this.indexOfKey(key));
12458 * Returns the number of items in the collection.
12459 * @return {Number} the number of items in the collection.
12461 getCount : function(){
12462 return this.length;
12466 * Returns index within the collection of the passed Object.
12467 * @param {Object} o The item to find the index of.
12468 * @return {Number} index of the item.
12470 indexOf : function(o){
12471 if(!this.items.indexOf){
12472 for(var i = 0, len = this.items.length; i < len; i++){
12473 if(this.items[i] == o) return i;
12477 return this.items.indexOf(o);
12482 * Returns index within the collection of the passed key.
12483 * @param {String} key The key to find the index of.
12484 * @return {Number} index of the key.
12486 indexOfKey : function(key){
12487 if(!this.keys.indexOf){
12488 for(var i = 0, len = this.keys.length; i < len; i++){
12489 if(this.keys[i] == key) return i;
12493 return this.keys.indexOf(key);
12498 * Returns the item associated with the passed key OR index. Key has priority over index.
12499 * @param {String/Number} key The key or index of the item.
12500 * @return {Object} The item associated with the passed key.
12502 item : function(key){
12503 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12504 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12508 * Returns the item at the specified index.
12509 * @param {Number} index The index of the item.
12512 itemAt : function(index){
12513 return this.items[index];
12517 * Returns the item associated with the passed key.
12518 * @param {String/Number} key The key of the item.
12519 * @return {Object} The item associated with the passed key.
12521 key : function(key){
12522 return this.map[key];
12526 * Returns true if the collection contains the passed Object as an item.
12527 * @param {Object} o The Object to look for in the collection.
12528 * @return {Boolean} True if the collection contains the Object as an item.
12530 contains : function(o){
12531 return this.indexOf(o) != -1;
12535 * Returns true if the collection contains the passed Object as a key.
12536 * @param {String} key The key to look for in the collection.
12537 * @return {Boolean} True if the collection contains the Object as a key.
12539 containsKey : function(key){
12540 return typeof this.map[key] != "undefined";
12544 * Removes all items from the collection.
12546 clear : function(){
12551 this.fireEvent("clear");
12555 * Returns the first item in the collection.
12556 * @return {Object} the first item in the collection..
12558 first : function(){
12559 return this.items[0];
12563 * Returns the last item in the collection.
12564 * @return {Object} the last item in the collection..
12567 return this.items[this.length-1];
12570 _sort : function(property, dir, fn){
12571 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12572 fn = fn || function(a, b){
12575 var c = [], k = this.keys, items = this.items;
12576 for(var i = 0, len = items.length; i < len; i++){
12577 c[c.length] = {key: k[i], value: items[i], index: i};
12579 c.sort(function(a, b){
12580 var v = fn(a[property], b[property]) * dsc;
12582 v = (a.index < b.index ? -1 : 1);
12586 for(var i = 0, len = c.length; i < len; i++){
12587 items[i] = c[i].value;
12590 this.fireEvent("sort", this);
12594 * Sorts this collection with the passed comparison function
12595 * @param {String} direction (optional) "ASC" or "DESC"
12596 * @param {Function} fn (optional) comparison function
12598 sort : function(dir, fn){
12599 this._sort("value", dir, fn);
12603 * Sorts this collection by keys
12604 * @param {String} direction (optional) "ASC" or "DESC"
12605 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12607 keySort : function(dir, fn){
12608 this._sort("key", dir, fn || function(a, b){
12609 return String(a).toUpperCase()-String(b).toUpperCase();
12614 * Returns a range of items in this collection
12615 * @param {Number} startIndex (optional) defaults to 0
12616 * @param {Number} endIndex (optional) default to the last item
12617 * @return {Array} An array of items
12619 getRange : function(start, end){
12620 var items = this.items;
12621 if(items.length < 1){
12624 start = start || 0;
12625 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12628 for(var i = start; i <= end; i++) {
12629 r[r.length] = items[i];
12632 for(var i = start; i >= end; i--) {
12633 r[r.length] = items[i];
12640 * Filter the <i>objects</i> in this collection by a specific property.
12641 * Returns a new collection that has been filtered.
12642 * @param {String} property A property on your objects
12643 * @param {String/RegExp} value Either string that the property values
12644 * should start with or a RegExp to test against the property
12645 * @return {MixedCollection} The new filtered collection
12647 filter : function(property, value){
12648 if(!value.exec){ // not a regex
12649 value = String(value);
12650 if(value.length == 0){
12651 return this.clone();
12653 value = new RegExp("^" + Roo.escapeRe(value), "i");
12655 return this.filterBy(function(o){
12656 return o && value.test(o[property]);
12661 * Filter by a function. * Returns a new collection that has been filtered.
12662 * The passed function will be called with each
12663 * object in the collection. If the function returns true, the value is included
12664 * otherwise it is filtered.
12665 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12666 * @param {Object} scope (optional) The scope of the function (defaults to this)
12667 * @return {MixedCollection} The new filtered collection
12669 filterBy : function(fn, scope){
12670 var r = new Roo.util.MixedCollection();
12671 r.getKey = this.getKey;
12672 var k = this.keys, it = this.items;
12673 for(var i = 0, len = it.length; i < len; i++){
12674 if(fn.call(scope||this, it[i], k[i])){
12675 r.add(k[i], it[i]);
12682 * Creates a duplicate of this collection
12683 * @return {MixedCollection}
12685 clone : function(){
12686 var r = new Roo.util.MixedCollection();
12687 var k = this.keys, it = this.items;
12688 for(var i = 0, len = it.length; i < len; i++){
12689 r.add(k[i], it[i]);
12691 r.getKey = this.getKey;
12696 * Returns the item associated with the passed key or index.
12698 * @param {String/Number} key The key or index of the item.
12699 * @return {Object} The item associated with the passed key.
12701 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12703 * Ext JS Library 1.1.1
12704 * Copyright(c) 2006-2007, Ext JS, LLC.
12706 * Originally Released Under LGPL - original licence link has changed is not relivant.
12709 * <script type="text/javascript">
12712 * @class Roo.util.JSON
12713 * Modified version of Douglas Crockford"s json.js that doesn"t
12714 * mess with the Object prototype
12715 * http://www.json.org/js.html
12718 Roo.util.JSON = new (function(){
12719 var useHasOwn = {}.hasOwnProperty ? true : false;
12721 // crashes Safari in some instances
12722 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12724 var pad = function(n) {
12725 return n < 10 ? "0" + n : n;
12738 var encodeString = function(s){
12739 if (/["\\\x00-\x1f]/.test(s)) {
12740 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12745 c = b.charCodeAt();
12747 Math.floor(c / 16).toString(16) +
12748 (c % 16).toString(16);
12751 return '"' + s + '"';
12754 var encodeArray = function(o){
12755 var a = ["["], b, i, l = o.length, v;
12756 for (i = 0; i < l; i += 1) {
12758 switch (typeof v) {
12767 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12775 var encodeDate = function(o){
12776 return '"' + o.getFullYear() + "-" +
12777 pad(o.getMonth() + 1) + "-" +
12778 pad(o.getDate()) + "T" +
12779 pad(o.getHours()) + ":" +
12780 pad(o.getMinutes()) + ":" +
12781 pad(o.getSeconds()) + '"';
12785 * Encodes an Object, Array or other value
12786 * @param {Mixed} o The variable to encode
12787 * @return {String} The JSON string
12789 this.encode = function(o)
12791 // should this be extended to fully wrap stringify..
12793 if(typeof o == "undefined" || o === null){
12795 }else if(o instanceof Array){
12796 return encodeArray(o);
12797 }else if(o instanceof Date){
12798 return encodeDate(o);
12799 }else if(typeof o == "string"){
12800 return encodeString(o);
12801 }else if(typeof o == "number"){
12802 return isFinite(o) ? String(o) : "null";
12803 }else if(typeof o == "boolean"){
12806 var a = ["{"], b, i, v;
12808 if(!useHasOwn || o.hasOwnProperty(i)) {
12810 switch (typeof v) {
12819 a.push(this.encode(i), ":",
12820 v === null ? "null" : this.encode(v));
12831 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12832 * @param {String} json The JSON string
12833 * @return {Object} The resulting object
12835 this.decode = function(json){
12837 return /** eval:var:json */ eval("(" + json + ')');
12841 * Shorthand for {@link Roo.util.JSON#encode}
12842 * @member Roo encode
12844 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12846 * Shorthand for {@link Roo.util.JSON#decode}
12847 * @member Roo decode
12849 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12852 * Ext JS Library 1.1.1
12853 * Copyright(c) 2006-2007, Ext JS, LLC.
12855 * Originally Released Under LGPL - original licence link has changed is not relivant.
12858 * <script type="text/javascript">
12862 * @class Roo.util.Format
12863 * Reusable data formatting functions
12866 Roo.util.Format = function(){
12867 var trimRe = /^\s+|\s+$/g;
12870 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12871 * @param {String} value The string to truncate
12872 * @param {Number} length The maximum length to allow before truncating
12873 * @return {String} The converted text
12875 ellipsis : function(value, len){
12876 if(value && value.length > len){
12877 return value.substr(0, len-3)+"...";
12883 * Checks a reference and converts it to empty string if it is undefined
12884 * @param {Mixed} value Reference to check
12885 * @return {Mixed} Empty string if converted, otherwise the original value
12887 undef : function(value){
12888 return typeof value != "undefined" ? value : "";
12892 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12893 * @param {String} value The string to encode
12894 * @return {String} The encoded text
12896 htmlEncode : function(value){
12897 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12901 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12902 * @param {String} value The string to decode
12903 * @return {String} The decoded text
12905 htmlDecode : function(value){
12906 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12910 * Trims any whitespace from either side of a string
12911 * @param {String} value The text to trim
12912 * @return {String} The trimmed text
12914 trim : function(value){
12915 return String(value).replace(trimRe, "");
12919 * Returns a substring from within an original string
12920 * @param {String} value The original text
12921 * @param {Number} start The start index of the substring
12922 * @param {Number} length The length of the substring
12923 * @return {String} The substring
12925 substr : function(value, start, length){
12926 return String(value).substr(start, length);
12930 * Converts a string to all lower case letters
12931 * @param {String} value The text to convert
12932 * @return {String} The converted text
12934 lowercase : function(value){
12935 return String(value).toLowerCase();
12939 * Converts a string to all upper case letters
12940 * @param {String} value The text to convert
12941 * @return {String} The converted text
12943 uppercase : function(value){
12944 return String(value).toUpperCase();
12948 * Converts the first character only of a string to upper case
12949 * @param {String} value The text to convert
12950 * @return {String} The converted text
12952 capitalize : function(value){
12953 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12957 call : function(value, fn){
12958 if(arguments.length > 2){
12959 var args = Array.prototype.slice.call(arguments, 2);
12960 args.unshift(value);
12962 return /** eval:var:value */ eval(fn).apply(window, args);
12964 /** eval:var:value */
12965 return /** eval:var:value */ eval(fn).call(window, value);
12971 * safer version of Math.toFixed..??/
12972 * @param {Number/String} value The numeric value to format
12973 * @param {Number/String} value Decimal places
12974 * @return {String} The formatted currency string
12976 toFixed : function(v, n)
12978 // why not use to fixed - precision is buggered???
12980 return Math.round(v-0);
12982 var fact = Math.pow(10,n+1);
12983 v = (Math.round((v-0)*fact))/fact;
12984 var z = (''+fact).substring(2);
12985 if (v == Math.floor(v)) {
12986 return Math.floor(v) + '.' + z;
12989 // now just padd decimals..
12990 var ps = String(v).split('.');
12991 var fd = (ps[1] + z);
12992 var r = fd.substring(0,n);
12993 var rm = fd.substring(n);
12995 return ps[0] + '.' + r;
12997 r*=1; // turn it into a number;
12999 if (String(r).length != n) {
13002 r = String(r).substring(1); // chop the end off.
13005 return ps[0] + '.' + r;
13010 * Format a number as US currency
13011 * @param {Number/String} value The numeric value to format
13012 * @return {String} The formatted currency string
13014 usMoney : function(v){
13015 v = (Math.round((v-0)*100))/100;
13016 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13018 var ps = v.split('.');
13020 var sub = ps[1] ? '.'+ ps[1] : '.00';
13021 var r = /(\d+)(\d{3})/;
13022 while (r.test(whole)) {
13023 whole = whole.replace(r, '$1' + ',' + '$2');
13025 return "$" + whole + sub ;
13029 * Parse a value into a formatted date using the specified format pattern.
13030 * @param {Mixed} value The value to format
13031 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13032 * @return {String} The formatted date string
13034 date : function(v, format){
13038 if(!(v instanceof Date)){
13039 v = new Date(Date.parse(v));
13041 return v.dateFormat(format || "m/d/Y");
13045 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13046 * @param {String} format Any valid date format string
13047 * @return {Function} The date formatting function
13049 dateRenderer : function(format){
13050 return function(v){
13051 return Roo.util.Format.date(v, format);
13056 stripTagsRE : /<\/?[^>]+>/gi,
13059 * Strips all HTML tags
13060 * @param {Mixed} value The text from which to strip tags
13061 * @return {String} The stripped text
13063 stripTags : function(v){
13064 return !v ? v : String(v).replace(this.stripTagsRE, "");
13069 * Ext JS Library 1.1.1
13070 * Copyright(c) 2006-2007, Ext JS, LLC.
13072 * Originally Released Under LGPL - original licence link has changed is not relivant.
13075 * <script type="text/javascript">
13082 * @class Roo.MasterTemplate
13083 * @extends Roo.Template
13084 * Provides a template that can have child templates. The syntax is:
13086 var t = new Roo.MasterTemplate(
13087 '<select name="{name}">',
13088 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13091 t.add('options', {value: 'foo', text: 'bar'});
13092 // or you can add multiple child elements in one shot
13093 t.addAll('options', [
13094 {value: 'foo', text: 'bar'},
13095 {value: 'foo2', text: 'bar2'},
13096 {value: 'foo3', text: 'bar3'}
13098 // then append, applying the master template values
13099 t.append('my-form', {name: 'my-select'});
13101 * A name attribute for the child template is not required if you have only one child
13102 * template or you want to refer to them by index.
13104 Roo.MasterTemplate = function(){
13105 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13106 this.originalHtml = this.html;
13108 var m, re = this.subTemplateRe;
13111 while(m = re.exec(this.html)){
13112 var name = m[1], content = m[2];
13117 tpl : new Roo.Template(content)
13120 st[name] = st[subIndex];
13122 st[subIndex].tpl.compile();
13123 st[subIndex].tpl.call = this.call.createDelegate(this);
13126 this.subCount = subIndex;
13129 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13131 * The regular expression used to match sub templates
13135 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13138 * Applies the passed values to a child template.
13139 * @param {String/Number} name (optional) The name or index of the child template
13140 * @param {Array/Object} values The values to be applied to the template
13141 * @return {MasterTemplate} this
13143 add : function(name, values){
13144 if(arguments.length == 1){
13145 values = arguments[0];
13148 var s = this.subs[name];
13149 s.buffer[s.buffer.length] = s.tpl.apply(values);
13154 * Applies all the passed values to a child template.
13155 * @param {String/Number} name (optional) The name or index of the child template
13156 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13157 * @param {Boolean} reset (optional) True to reset the template first
13158 * @return {MasterTemplate} this
13160 fill : function(name, values, reset){
13162 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13170 for(var i = 0, len = values.length; i < len; i++){
13171 this.add(name, values[i]);
13177 * Resets the template for reuse
13178 * @return {MasterTemplate} this
13180 reset : function(){
13182 for(var i = 0; i < this.subCount; i++){
13188 applyTemplate : function(values){
13190 var replaceIndex = -1;
13191 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13192 return s[++replaceIndex].buffer.join("");
13194 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13197 apply : function(){
13198 return this.applyTemplate.apply(this, arguments);
13201 compile : function(){return this;}
13205 * Alias for fill().
13208 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13210 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13211 * var tpl = Roo.MasterTemplate.from('element-id');
13212 * @param {String/HTMLElement} el
13213 * @param {Object} config
13216 Roo.MasterTemplate.from = function(el, config){
13217 el = Roo.getDom(el);
13218 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13221 * Ext JS Library 1.1.1
13222 * Copyright(c) 2006-2007, Ext JS, LLC.
13224 * Originally Released Under LGPL - original licence link has changed is not relivant.
13227 * <script type="text/javascript">
13232 * @class Roo.util.CSS
13233 * Utility class for manipulating CSS rules
13236 Roo.util.CSS = function(){
13238 var doc = document;
13240 var camelRe = /(-[a-z])/gi;
13241 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13245 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13246 * tag and appended to the HEAD of the document.
13247 * @param {String|Object} cssText The text containing the css rules
13248 * @param {String} id An id to add to the stylesheet for later removal
13249 * @return {StyleSheet}
13251 createStyleSheet : function(cssText, id){
13253 var head = doc.getElementsByTagName("head")[0];
13254 var nrules = doc.createElement("style");
13255 nrules.setAttribute("type", "text/css");
13257 nrules.setAttribute("id", id);
13259 if (typeof(cssText) != 'string') {
13260 // support object maps..
13261 // not sure if this a good idea..
13262 // perhaps it should be merged with the general css handling
13263 // and handle js style props.
13264 var cssTextNew = [];
13265 for(var n in cssText) {
13267 for(var k in cssText[n]) {
13268 citems.push( k + ' : ' +cssText[n][k] + ';' );
13270 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13273 cssText = cssTextNew.join("\n");
13279 head.appendChild(nrules);
13280 ss = nrules.styleSheet;
13281 ss.cssText = cssText;
13284 nrules.appendChild(doc.createTextNode(cssText));
13286 nrules.cssText = cssText;
13288 head.appendChild(nrules);
13289 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13291 this.cacheStyleSheet(ss);
13296 * Removes a style or link tag by id
13297 * @param {String} id The id of the tag
13299 removeStyleSheet : function(id){
13300 var existing = doc.getElementById(id);
13302 existing.parentNode.removeChild(existing);
13307 * Dynamically swaps an existing stylesheet reference for a new one
13308 * @param {String} id The id of an existing link tag to remove
13309 * @param {String} url The href of the new stylesheet to include
13311 swapStyleSheet : function(id, url){
13312 this.removeStyleSheet(id);
13313 var ss = doc.createElement("link");
13314 ss.setAttribute("rel", "stylesheet");
13315 ss.setAttribute("type", "text/css");
13316 ss.setAttribute("id", id);
13317 ss.setAttribute("href", url);
13318 doc.getElementsByTagName("head")[0].appendChild(ss);
13322 * Refresh the rule cache if you have dynamically added stylesheets
13323 * @return {Object} An object (hash) of rules indexed by selector
13325 refreshCache : function(){
13326 return this.getRules(true);
13330 cacheStyleSheet : function(stylesheet){
13334 try{// try catch for cross domain access issue
13335 var ssRules = stylesheet.cssRules || stylesheet.rules;
13336 for(var j = ssRules.length-1; j >= 0; --j){
13337 rules[ssRules[j].selectorText] = ssRules[j];
13343 * Gets all css rules for the document
13344 * @param {Boolean} refreshCache true to refresh the internal cache
13345 * @return {Object} An object (hash) of rules indexed by selector
13347 getRules : function(refreshCache){
13348 if(rules == null || refreshCache){
13350 var ds = doc.styleSheets;
13351 for(var i =0, len = ds.length; i < len; i++){
13353 this.cacheStyleSheet(ds[i]);
13361 * Gets an an individual CSS rule by selector(s)
13362 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13363 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13364 * @return {CSSRule} The CSS rule or null if one is not found
13366 getRule : function(selector, refreshCache){
13367 var rs = this.getRules(refreshCache);
13368 if(!(selector instanceof Array)){
13369 return rs[selector];
13371 for(var i = 0; i < selector.length; i++){
13372 if(rs[selector[i]]){
13373 return rs[selector[i]];
13381 * Updates a rule property
13382 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13383 * @param {String} property The css property
13384 * @param {String} value The new value for the property
13385 * @return {Boolean} true If a rule was found and updated
13387 updateRule : function(selector, property, value){
13388 if(!(selector instanceof Array)){
13389 var rule = this.getRule(selector);
13391 rule.style[property.replace(camelRe, camelFn)] = value;
13395 for(var i = 0; i < selector.length; i++){
13396 if(this.updateRule(selector[i], property, value)){
13406 * Ext JS Library 1.1.1
13407 * Copyright(c) 2006-2007, Ext JS, LLC.
13409 * Originally Released Under LGPL - original licence link has changed is not relivant.
13412 * <script type="text/javascript">
13418 * @class Roo.util.ClickRepeater
13419 * @extends Roo.util.Observable
13421 * A wrapper class which can be applied to any element. Fires a "click" event while the
13422 * mouse is pressed. The interval between firings may be specified in the config but
13423 * defaults to 10 milliseconds.
13425 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13427 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13428 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13429 * Similar to an autorepeat key delay.
13430 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13431 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13432 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13433 * "interval" and "delay" are ignored. "immediate" is honored.
13434 * @cfg {Boolean} preventDefault True to prevent the default click event
13435 * @cfg {Boolean} stopDefault True to stop the default click event
13438 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13439 * 2007-02-02 jvs Renamed to ClickRepeater
13440 * 2007-02-03 jvs Modifications for FF Mac and Safari
13443 * @param {String/HTMLElement/Element} el The element to listen on
13444 * @param {Object} config
13446 Roo.util.ClickRepeater = function(el, config)
13448 this.el = Roo.get(el);
13449 this.el.unselectable();
13451 Roo.apply(this, config);
13456 * Fires when the mouse button is depressed.
13457 * @param {Roo.util.ClickRepeater} this
13459 "mousedown" : true,
13462 * Fires on a specified interval during the time the element is pressed.
13463 * @param {Roo.util.ClickRepeater} this
13468 * Fires when the mouse key is released.
13469 * @param {Roo.util.ClickRepeater} this
13474 this.el.on("mousedown", this.handleMouseDown, this);
13475 if(this.preventDefault || this.stopDefault){
13476 this.el.on("click", function(e){
13477 if(this.preventDefault){
13478 e.preventDefault();
13480 if(this.stopDefault){
13486 // allow inline handler
13488 this.on("click", this.handler, this.scope || this);
13491 Roo.util.ClickRepeater.superclass.constructor.call(this);
13494 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13497 preventDefault : true,
13498 stopDefault : false,
13502 handleMouseDown : function(){
13503 clearTimeout(this.timer);
13505 if(this.pressClass){
13506 this.el.addClass(this.pressClass);
13508 this.mousedownTime = new Date();
13510 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13511 this.el.on("mouseout", this.handleMouseOut, this);
13513 this.fireEvent("mousedown", this);
13514 this.fireEvent("click", this);
13516 this.timer = this.click.defer(this.delay || this.interval, this);
13520 click : function(){
13521 this.fireEvent("click", this);
13522 this.timer = this.click.defer(this.getInterval(), this);
13526 getInterval: function(){
13527 if(!this.accelerate){
13528 return this.interval;
13530 var pressTime = this.mousedownTime.getElapsed();
13531 if(pressTime < 500){
13533 }else if(pressTime < 1700){
13535 }else if(pressTime < 2600){
13537 }else if(pressTime < 3500){
13539 }else if(pressTime < 4400){
13541 }else if(pressTime < 5300){
13543 }else if(pressTime < 6200){
13551 handleMouseOut : function(){
13552 clearTimeout(this.timer);
13553 if(this.pressClass){
13554 this.el.removeClass(this.pressClass);
13556 this.el.on("mouseover", this.handleMouseReturn, this);
13560 handleMouseReturn : function(){
13561 this.el.un("mouseover", this.handleMouseReturn);
13562 if(this.pressClass){
13563 this.el.addClass(this.pressClass);
13569 handleMouseUp : function(){
13570 clearTimeout(this.timer);
13571 this.el.un("mouseover", this.handleMouseReturn);
13572 this.el.un("mouseout", this.handleMouseOut);
13573 Roo.get(document).un("mouseup", this.handleMouseUp);
13574 this.el.removeClass(this.pressClass);
13575 this.fireEvent("mouseup", this);
13579 * Ext JS Library 1.1.1
13580 * Copyright(c) 2006-2007, Ext JS, LLC.
13582 * Originally Released Under LGPL - original licence link has changed is not relivant.
13585 * <script type="text/javascript">
13590 * @class Roo.KeyNav
13591 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13592 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13593 * way to implement custom navigation schemes for any UI component.</p>
13594 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13595 * pageUp, pageDown, del, home, end. Usage:</p>
13597 var nav = new Roo.KeyNav("my-element", {
13598 "left" : function(e){
13599 this.moveLeft(e.ctrlKey);
13601 "right" : function(e){
13602 this.moveRight(e.ctrlKey);
13604 "enter" : function(e){
13611 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13612 * @param {Object} config The config
13614 Roo.KeyNav = function(el, config){
13615 this.el = Roo.get(el);
13616 Roo.apply(this, config);
13617 if(!this.disabled){
13618 this.disabled = true;
13623 Roo.KeyNav.prototype = {
13625 * @cfg {Boolean} disabled
13626 * True to disable this KeyNav instance (defaults to false)
13630 * @cfg {String} defaultEventAction
13631 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13632 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13633 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13635 defaultEventAction: "stopEvent",
13637 * @cfg {Boolean} forceKeyDown
13638 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13639 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13640 * handle keydown instead of keypress.
13642 forceKeyDown : false,
13645 prepareEvent : function(e){
13646 var k = e.getKey();
13647 var h = this.keyToHandler[k];
13648 //if(h && this[h]){
13649 // e.stopPropagation();
13651 if(Roo.isSafari && h && k >= 37 && k <= 40){
13657 relay : function(e){
13658 var k = e.getKey();
13659 var h = this.keyToHandler[k];
13661 if(this.doRelay(e, this[h], h) !== true){
13662 e[this.defaultEventAction]();
13668 doRelay : function(e, h, hname){
13669 return h.call(this.scope || this, e);
13672 // possible handlers
13686 // quick lookup hash
13703 * Enable this KeyNav
13705 enable: function(){
13707 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13708 // the EventObject will normalize Safari automatically
13709 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13710 this.el.on("keydown", this.relay, this);
13712 this.el.on("keydown", this.prepareEvent, this);
13713 this.el.on("keypress", this.relay, this);
13715 this.disabled = false;
13720 * Disable this KeyNav
13722 disable: function(){
13723 if(!this.disabled){
13724 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13725 this.el.un("keydown", this.relay);
13727 this.el.un("keydown", this.prepareEvent);
13728 this.el.un("keypress", this.relay);
13730 this.disabled = true;
13735 * Ext JS Library 1.1.1
13736 * Copyright(c) 2006-2007, Ext JS, LLC.
13738 * Originally Released Under LGPL - original licence link has changed is not relivant.
13741 * <script type="text/javascript">
13746 * @class Roo.KeyMap
13747 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13748 * The constructor accepts the same config object as defined by {@link #addBinding}.
13749 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13750 * combination it will call the function with this signature (if the match is a multi-key
13751 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13752 * A KeyMap can also handle a string representation of keys.<br />
13755 // map one key by key code
13756 var map = new Roo.KeyMap("my-element", {
13757 key: 13, // or Roo.EventObject.ENTER
13762 // map multiple keys to one action by string
13763 var map = new Roo.KeyMap("my-element", {
13769 // map multiple keys to multiple actions by strings and array of codes
13770 var map = new Roo.KeyMap("my-element", [
13773 fn: function(){ alert("Return was pressed"); }
13776 fn: function(){ alert('a, b or c was pressed'); }
13781 fn: function(){ alert('Control + shift + tab was pressed.'); }
13785 * <b>Note: A KeyMap starts enabled</b>
13787 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13788 * @param {Object} config The config (see {@link #addBinding})
13789 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13791 Roo.KeyMap = function(el, config, eventName){
13792 this.el = Roo.get(el);
13793 this.eventName = eventName || "keydown";
13794 this.bindings = [];
13796 this.addBinding(config);
13801 Roo.KeyMap.prototype = {
13803 * True to stop the event from bubbling and prevent the default browser action if the
13804 * key was handled by the KeyMap (defaults to false)
13810 * Add a new binding to this KeyMap. The following config object properties are supported:
13812 Property Type Description
13813 ---------- --------------- ----------------------------------------------------------------------
13814 key String/Array A single keycode or an array of keycodes to handle
13815 shift Boolean True to handle key only when shift is pressed (defaults to false)
13816 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13817 alt Boolean True to handle key only when alt is pressed (defaults to false)
13818 fn Function The function to call when KeyMap finds the expected key combination
13819 scope Object The scope of the callback function
13825 var map = new Roo.KeyMap(document, {
13826 key: Roo.EventObject.ENTER,
13831 //Add a new binding to the existing KeyMap later
13839 * @param {Object/Array} config A single KeyMap config or an array of configs
13841 addBinding : function(config){
13842 if(config instanceof Array){
13843 for(var i = 0, len = config.length; i < len; i++){
13844 this.addBinding(config[i]);
13848 var keyCode = config.key,
13849 shift = config.shift,
13850 ctrl = config.ctrl,
13853 scope = config.scope;
13854 if(typeof keyCode == "string"){
13856 var keyString = keyCode.toUpperCase();
13857 for(var j = 0, len = keyString.length; j < len; j++){
13858 ks.push(keyString.charCodeAt(j));
13862 var keyArray = keyCode instanceof Array;
13863 var handler = function(e){
13864 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13865 var k = e.getKey();
13867 for(var i = 0, len = keyCode.length; i < len; i++){
13868 if(keyCode[i] == k){
13869 if(this.stopEvent){
13872 fn.call(scope || window, k, e);
13878 if(this.stopEvent){
13881 fn.call(scope || window, k, e);
13886 this.bindings.push(handler);
13890 * Shorthand for adding a single key listener
13891 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13892 * following options:
13893 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13894 * @param {Function} fn The function to call
13895 * @param {Object} scope (optional) The scope of the function
13897 on : function(key, fn, scope){
13898 var keyCode, shift, ctrl, alt;
13899 if(typeof key == "object" && !(key instanceof Array)){
13918 handleKeyDown : function(e){
13919 if(this.enabled){ //just in case
13920 var b = this.bindings;
13921 for(var i = 0, len = b.length; i < len; i++){
13922 b[i].call(this, e);
13928 * Returns true if this KeyMap is enabled
13929 * @return {Boolean}
13931 isEnabled : function(){
13932 return this.enabled;
13936 * Enables this KeyMap
13938 enable: function(){
13940 this.el.on(this.eventName, this.handleKeyDown, this);
13941 this.enabled = true;
13946 * Disable this KeyMap
13948 disable: function(){
13950 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13951 this.enabled = false;
13956 * Ext JS Library 1.1.1
13957 * Copyright(c) 2006-2007, Ext JS, LLC.
13959 * Originally Released Under LGPL - original licence link has changed is not relivant.
13962 * <script type="text/javascript">
13967 * @class Roo.util.TextMetrics
13968 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13969 * wide, in pixels, a given block of text will be.
13972 Roo.util.TextMetrics = function(){
13976 * Measures the size of the specified text
13977 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13978 * that can affect the size of the rendered text
13979 * @param {String} text The text to measure
13980 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13981 * in order to accurately measure the text height
13982 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13984 measure : function(el, text, fixedWidth){
13986 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13989 shared.setFixedWidth(fixedWidth || 'auto');
13990 return shared.getSize(text);
13994 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13995 * the overhead of multiple calls to initialize the style properties on each measurement.
13996 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13997 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13998 * in order to accurately measure the text height
13999 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14001 createInstance : function(el, fixedWidth){
14002 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14009 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14010 var ml = new Roo.Element(document.createElement('div'));
14011 document.body.appendChild(ml.dom);
14012 ml.position('absolute');
14013 ml.setLeftTop(-1000, -1000);
14017 ml.setWidth(fixedWidth);
14022 * Returns the size of the specified text based on the internal element's style and width properties
14023 * @memberOf Roo.util.TextMetrics.Instance#
14024 * @param {String} text The text to measure
14025 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14027 getSize : function(text){
14029 var s = ml.getSize();
14035 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14036 * that can affect the size of the rendered text
14037 * @memberOf Roo.util.TextMetrics.Instance#
14038 * @param {String/HTMLElement} el The element, dom node or id
14040 bind : function(el){
14042 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14047 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14048 * to set a fixed width in order to accurately measure the text height.
14049 * @memberOf Roo.util.TextMetrics.Instance#
14050 * @param {Number} width The width to set on the element
14052 setFixedWidth : function(width){
14053 ml.setWidth(width);
14057 * Returns the measured width of the specified text
14058 * @memberOf Roo.util.TextMetrics.Instance#
14059 * @param {String} text The text to measure
14060 * @return {Number} width The width in pixels
14062 getWidth : function(text){
14063 ml.dom.style.width = 'auto';
14064 return this.getSize(text).width;
14068 * Returns the measured height of the specified text. For multiline text, be sure to call
14069 * {@link #setFixedWidth} if necessary.
14070 * @memberOf Roo.util.TextMetrics.Instance#
14071 * @param {String} text The text to measure
14072 * @return {Number} height The height in pixels
14074 getHeight : function(text){
14075 return this.getSize(text).height;
14079 instance.bind(bindTo);
14084 // backwards compat
14085 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14087 * Ext JS Library 1.1.1
14088 * Copyright(c) 2006-2007, Ext JS, LLC.
14090 * Originally Released Under LGPL - original licence link has changed is not relivant.
14093 * <script type="text/javascript">
14097 * @class Roo.state.Provider
14098 * Abstract base class for state provider implementations. This class provides methods
14099 * for encoding and decoding <b>typed</b> variables including dates and defines the
14100 * Provider interface.
14102 Roo.state.Provider = function(){
14104 * @event statechange
14105 * Fires when a state change occurs.
14106 * @param {Provider} this This state provider
14107 * @param {String} key The state key which was changed
14108 * @param {String} value The encoded value for the state
14111 "statechange": true
14114 Roo.state.Provider.superclass.constructor.call(this);
14116 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14118 * Returns the current value for a key
14119 * @param {String} name The key name
14120 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14121 * @return {Mixed} The state data
14123 get : function(name, defaultValue){
14124 return typeof this.state[name] == "undefined" ?
14125 defaultValue : this.state[name];
14129 * Clears a value from the state
14130 * @param {String} name The key name
14132 clear : function(name){
14133 delete this.state[name];
14134 this.fireEvent("statechange", this, name, null);
14138 * Sets the value for a key
14139 * @param {String} name The key name
14140 * @param {Mixed} value The value to set
14142 set : function(name, value){
14143 this.state[name] = value;
14144 this.fireEvent("statechange", this, name, value);
14148 * Decodes a string previously encoded with {@link #encodeValue}.
14149 * @param {String} value The value to decode
14150 * @return {Mixed} The decoded value
14152 decodeValue : function(cookie){
14153 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14154 var matches = re.exec(unescape(cookie));
14155 if(!matches || !matches[1]) return; // non state cookie
14156 var type = matches[1];
14157 var v = matches[2];
14160 return parseFloat(v);
14162 return new Date(Date.parse(v));
14167 var values = v.split("^");
14168 for(var i = 0, len = values.length; i < len; i++){
14169 all.push(this.decodeValue(values[i]));
14174 var values = v.split("^");
14175 for(var i = 0, len = values.length; i < len; i++){
14176 var kv = values[i].split("=");
14177 all[kv[0]] = this.decodeValue(kv[1]);
14186 * Encodes a value including type information. Decode with {@link #decodeValue}.
14187 * @param {Mixed} value The value to encode
14188 * @return {String} The encoded value
14190 encodeValue : function(v){
14192 if(typeof v == "number"){
14194 }else if(typeof v == "boolean"){
14195 enc = "b:" + (v ? "1" : "0");
14196 }else if(v instanceof Date){
14197 enc = "d:" + v.toGMTString();
14198 }else if(v instanceof Array){
14200 for(var i = 0, len = v.length; i < len; i++){
14201 flat += this.encodeValue(v[i]);
14202 if(i != len-1) flat += "^";
14205 }else if(typeof v == "object"){
14208 if(typeof v[key] != "function"){
14209 flat += key + "=" + this.encodeValue(v[key]) + "^";
14212 enc = "o:" + flat.substring(0, flat.length-1);
14216 return escape(enc);
14222 * Ext JS Library 1.1.1
14223 * Copyright(c) 2006-2007, Ext JS, LLC.
14225 * Originally Released Under LGPL - original licence link has changed is not relivant.
14228 * <script type="text/javascript">
14231 * @class Roo.state.Manager
14232 * This is the global state manager. By default all components that are "state aware" check this class
14233 * for state information if you don't pass them a custom state provider. In order for this class
14234 * to be useful, it must be initialized with a provider when your application initializes.
14236 // in your initialization function
14238 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14240 // supposed you have a {@link Roo.BorderLayout}
14241 var layout = new Roo.BorderLayout(...);
14242 layout.restoreState();
14243 // or a {Roo.BasicDialog}
14244 var dialog = new Roo.BasicDialog(...);
14245 dialog.restoreState();
14249 Roo.state.Manager = function(){
14250 var provider = new Roo.state.Provider();
14254 * Configures the default state provider for your application
14255 * @param {Provider} stateProvider The state provider to set
14257 setProvider : function(stateProvider){
14258 provider = stateProvider;
14262 * Returns the current value for a key
14263 * @param {String} name The key name
14264 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14265 * @return {Mixed} The state data
14267 get : function(key, defaultValue){
14268 return provider.get(key, defaultValue);
14272 * Sets the value for a key
14273 * @param {String} name The key name
14274 * @param {Mixed} value The state data
14276 set : function(key, value){
14277 provider.set(key, value);
14281 * Clears a value from the state
14282 * @param {String} name The key name
14284 clear : function(key){
14285 provider.clear(key);
14289 * Gets the currently configured state provider
14290 * @return {Provider} The state provider
14292 getProvider : function(){
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">
14308 * @class Roo.state.CookieProvider
14309 * @extends Roo.state.Provider
14310 * The default Provider implementation which saves state via cookies.
14313 var cp = new Roo.state.CookieProvider({
14315 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14316 domain: "roojs.com"
14318 Roo.state.Manager.setProvider(cp);
14320 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14321 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14322 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14323 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14324 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14325 * domain the page is running on including the 'www' like 'www.roojs.com')
14326 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14328 * Create a new CookieProvider
14329 * @param {Object} config The configuration object
14331 Roo.state.CookieProvider = function(config){
14332 Roo.state.CookieProvider.superclass.constructor.call(this);
14334 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14335 this.domain = null;
14336 this.secure = false;
14337 Roo.apply(this, config);
14338 this.state = this.readCookies();
14341 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14343 set : function(name, value){
14344 if(typeof value == "undefined" || value === null){
14348 this.setCookie(name, value);
14349 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14353 clear : function(name){
14354 this.clearCookie(name);
14355 Roo.state.CookieProvider.superclass.clear.call(this, name);
14359 readCookies : function(){
14361 var c = document.cookie + ";";
14362 var re = /\s?(.*?)=(.*?);/g;
14364 while((matches = re.exec(c)) != null){
14365 var name = matches[1];
14366 var value = matches[2];
14367 if(name && name.substring(0,3) == "ys-"){
14368 cookies[name.substr(3)] = this.decodeValue(value);
14375 setCookie : function(name, value){
14376 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14377 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14378 ((this.path == null) ? "" : ("; path=" + this.path)) +
14379 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14380 ((this.secure == true) ? "; secure" : "");
14384 clearCookie : function(name){
14385 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14386 ((this.path == null) ? "" : ("; path=" + this.path)) +
14387 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14388 ((this.secure == true) ? "; secure" : "");
14392 * Ext JS Library 1.1.1
14393 * Copyright(c) 2006-2007, Ext JS, LLC.
14395 * Originally Released Under LGPL - original licence link has changed is not relivant.
14398 * <script type="text/javascript">
14404 * These classes are derivatives of the similarly named classes in the YUI Library.
14405 * The original license:
14406 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14407 * Code licensed under the BSD License:
14408 * http://developer.yahoo.net/yui/license.txt
14413 var Event=Roo.EventManager;
14414 var Dom=Roo.lib.Dom;
14417 * @class Roo.dd.DragDrop
14418 * @extends Roo.util.Observable
14419 * Defines the interface and base operation of items that that can be
14420 * dragged or can be drop targets. It was designed to be extended, overriding
14421 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14422 * Up to three html elements can be associated with a DragDrop instance:
14424 * <li>linked element: the element that is passed into the constructor.
14425 * This is the element which defines the boundaries for interaction with
14426 * other DragDrop objects.</li>
14427 * <li>handle element(s): The drag operation only occurs if the element that
14428 * was clicked matches a handle element. By default this is the linked
14429 * element, but there are times that you will want only a portion of the
14430 * linked element to initiate the drag operation, and the setHandleElId()
14431 * method provides a way to define this.</li>
14432 * <li>drag element: this represents the element that would be moved along
14433 * with the cursor during a drag operation. By default, this is the linked
14434 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14435 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14438 * This class should not be instantiated until the onload event to ensure that
14439 * the associated elements are available.
14440 * The following would define a DragDrop obj that would interact with any
14441 * other DragDrop obj in the "group1" group:
14443 * dd = new Roo.dd.DragDrop("div1", "group1");
14445 * Since none of the event handlers have been implemented, nothing would
14446 * actually happen if you were to run the code above. Normally you would
14447 * override this class or one of the default implementations, but you can
14448 * also override the methods you want on an instance of the class...
14450 * dd.onDragDrop = function(e, id) {
14451 * alert("dd was dropped on " + id);
14455 * @param {String} id of the element that is linked to this instance
14456 * @param {String} sGroup the group of related DragDrop objects
14457 * @param {object} config an object containing configurable attributes
14458 * Valid properties for DragDrop:
14459 * padding, isTarget, maintainOffset, primaryButtonOnly
14461 Roo.dd.DragDrop = function(id, sGroup, config) {
14463 this.init(id, sGroup, config);
14468 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14471 * The id of the element associated with this object. This is what we
14472 * refer to as the "linked element" because the size and position of
14473 * this element is used to determine when the drag and drop objects have
14481 * Configuration attributes passed into the constructor
14488 * The id of the element that will be dragged. By default this is same
14489 * as the linked element , but could be changed to another element. Ex:
14491 * @property dragElId
14498 * the id of the element that initiates the drag operation. By default
14499 * this is the linked element, but could be changed to be a child of this
14500 * element. This lets us do things like only starting the drag when the
14501 * header element within the linked html element is clicked.
14502 * @property handleElId
14509 * An associative array of HTML tags that will be ignored if clicked.
14510 * @property invalidHandleTypes
14511 * @type {string: string}
14513 invalidHandleTypes: null,
14516 * An associative array of ids for elements that will be ignored if clicked
14517 * @property invalidHandleIds
14518 * @type {string: string}
14520 invalidHandleIds: null,
14523 * An indexted array of css class names for elements that will be ignored
14525 * @property invalidHandleClasses
14528 invalidHandleClasses: null,
14531 * The linked element's absolute X position at the time the drag was
14533 * @property startPageX
14540 * The linked element's absolute X position at the time the drag was
14542 * @property startPageY
14549 * The group defines a logical collection of DragDrop objects that are
14550 * related. Instances only get events when interacting with other
14551 * DragDrop object in the same group. This lets us define multiple
14552 * groups using a single DragDrop subclass if we want.
14554 * @type {string: string}
14559 * Individual drag/drop instances can be locked. This will prevent
14560 * onmousedown start drag.
14568 * Lock this instance
14571 lock: function() { this.locked = true; },
14574 * Unlock this instace
14577 unlock: function() { this.locked = false; },
14580 * By default, all insances can be a drop target. This can be disabled by
14581 * setting isTarget to false.
14588 * The padding configured for this drag and drop object for calculating
14589 * the drop zone intersection with this object.
14596 * Cached reference to the linked element
14597 * @property _domRef
14603 * Internal typeof flag
14604 * @property __ygDragDrop
14607 __ygDragDrop: true,
14610 * Set to true when horizontal contraints are applied
14611 * @property constrainX
14618 * Set to true when vertical contraints are applied
14619 * @property constrainY
14626 * The left constraint
14634 * The right constraint
14642 * The up constraint
14651 * The down constraint
14659 * Maintain offsets when we resetconstraints. Set to true when you want
14660 * the position of the element relative to its parent to stay the same
14661 * when the page changes
14663 * @property maintainOffset
14666 maintainOffset: false,
14669 * Array of pixel locations the element will snap to if we specified a
14670 * horizontal graduation/interval. This array is generated automatically
14671 * when you define a tick interval.
14678 * Array of pixel locations the element will snap to if we specified a
14679 * vertical graduation/interval. This array is generated automatically
14680 * when you define a tick interval.
14687 * By default the drag and drop instance will only respond to the primary
14688 * button click (left button for a right-handed mouse). Set to true to
14689 * allow drag and drop to start with any mouse click that is propogated
14691 * @property primaryButtonOnly
14694 primaryButtonOnly: true,
14697 * The availabe property is false until the linked dom element is accessible.
14698 * @property available
14704 * By default, drags can only be initiated if the mousedown occurs in the
14705 * region the linked element is. This is done in part to work around a
14706 * bug in some browsers that mis-report the mousedown if the previous
14707 * mouseup happened outside of the window. This property is set to true
14708 * if outer handles are defined.
14710 * @property hasOuterHandles
14714 hasOuterHandles: false,
14717 * Code that executes immediately before the startDrag event
14718 * @method b4StartDrag
14721 b4StartDrag: function(x, y) { },
14724 * Abstract method called after a drag/drop object is clicked
14725 * and the drag or mousedown time thresholds have beeen met.
14726 * @method startDrag
14727 * @param {int} X click location
14728 * @param {int} Y click location
14730 startDrag: function(x, y) { /* override this */ },
14733 * Code that executes immediately before the onDrag event
14737 b4Drag: function(e) { },
14740 * Abstract method called during the onMouseMove event while dragging an
14743 * @param {Event} e the mousemove event
14745 onDrag: function(e) { /* override this */ },
14748 * Abstract method called when this element fist begins hovering over
14749 * another DragDrop obj
14750 * @method onDragEnter
14751 * @param {Event} e the mousemove event
14752 * @param {String|DragDrop[]} id In POINT mode, the element
14753 * id this is hovering over. In INTERSECT mode, an array of one or more
14754 * dragdrop items being hovered over.
14756 onDragEnter: function(e, id) { /* override this */ },
14759 * Code that executes immediately before the onDragOver event
14760 * @method b4DragOver
14763 b4DragOver: function(e) { },
14766 * Abstract method called when this element is hovering over another
14768 * @method onDragOver
14769 * @param {Event} e the mousemove event
14770 * @param {String|DragDrop[]} id In POINT mode, the element
14771 * id this is hovering over. In INTERSECT mode, an array of dd items
14772 * being hovered over.
14774 onDragOver: function(e, id) { /* override this */ },
14777 * Code that executes immediately before the onDragOut event
14778 * @method b4DragOut
14781 b4DragOut: function(e) { },
14784 * Abstract method called when we are no longer hovering over an element
14785 * @method onDragOut
14786 * @param {Event} e the mousemove event
14787 * @param {String|DragDrop[]} id In POINT mode, the element
14788 * id this was hovering over. In INTERSECT mode, an array of dd items
14789 * that the mouse is no longer over.
14791 onDragOut: function(e, id) { /* override this */ },
14794 * Code that executes immediately before the onDragDrop event
14795 * @method b4DragDrop
14798 b4DragDrop: function(e) { },
14801 * Abstract method called when this item is dropped on another DragDrop
14803 * @method onDragDrop
14804 * @param {Event} e the mouseup event
14805 * @param {String|DragDrop[]} id In POINT mode, the element
14806 * id this was dropped on. In INTERSECT mode, an array of dd items this
14809 onDragDrop: function(e, id) { /* override this */ },
14812 * Abstract method called when this item is dropped on an area with no
14814 * @method onInvalidDrop
14815 * @param {Event} e the mouseup event
14817 onInvalidDrop: function(e) { /* override this */ },
14820 * Code that executes immediately before the endDrag event
14821 * @method b4EndDrag
14824 b4EndDrag: function(e) { },
14827 * Fired when we are done dragging the object
14829 * @param {Event} e the mouseup event
14831 endDrag: function(e) { /* override this */ },
14834 * Code executed immediately before the onMouseDown event
14835 * @method b4MouseDown
14836 * @param {Event} e the mousedown event
14839 b4MouseDown: function(e) { },
14842 * Event handler that fires when a drag/drop obj gets a mousedown
14843 * @method onMouseDown
14844 * @param {Event} e the mousedown event
14846 onMouseDown: function(e) { /* override this */ },
14849 * Event handler that fires when a drag/drop obj gets a mouseup
14850 * @method onMouseUp
14851 * @param {Event} e the mouseup event
14853 onMouseUp: function(e) { /* override this */ },
14856 * Override the onAvailable method to do what is needed after the initial
14857 * position was determined.
14858 * @method onAvailable
14860 onAvailable: function () {
14864 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14867 defaultPadding : {left:0, right:0, top:0, bottom:0},
14870 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14874 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14875 { dragElId: "existingProxyDiv" });
14876 dd.startDrag = function(){
14877 this.constrainTo("parent-id");
14880 * Or you can initalize it using the {@link Roo.Element} object:
14882 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14883 startDrag : function(){
14884 this.constrainTo("parent-id");
14888 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14889 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14890 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14891 * an object containing the sides to pad. For example: {right:10, bottom:10}
14892 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14894 constrainTo : function(constrainTo, pad, inContent){
14895 if(typeof pad == "number"){
14896 pad = {left: pad, right:pad, top:pad, bottom:pad};
14898 pad = pad || this.defaultPadding;
14899 var b = Roo.get(this.getEl()).getBox();
14900 var ce = Roo.get(constrainTo);
14901 var s = ce.getScroll();
14902 var c, cd = ce.dom;
14903 if(cd == document.body){
14904 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14907 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14911 var topSpace = b.y - c.y;
14912 var leftSpace = b.x - c.x;
14914 this.resetConstraints();
14915 this.setXConstraint(leftSpace - (pad.left||0), // left
14916 c.width - leftSpace - b.width - (pad.right||0) //right
14918 this.setYConstraint(topSpace - (pad.top||0), //top
14919 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14924 * Returns a reference to the linked element
14926 * @return {HTMLElement} the html element
14928 getEl: function() {
14929 if (!this._domRef) {
14930 this._domRef = Roo.getDom(this.id);
14933 return this._domRef;
14937 * Returns a reference to the actual element to drag. By default this is
14938 * the same as the html element, but it can be assigned to another
14939 * element. An example of this can be found in Roo.dd.DDProxy
14940 * @method getDragEl
14941 * @return {HTMLElement} the html element
14943 getDragEl: function() {
14944 return Roo.getDom(this.dragElId);
14948 * Sets up the DragDrop object. Must be called in the constructor of any
14949 * Roo.dd.DragDrop subclass
14951 * @param id the id of the linked element
14952 * @param {String} sGroup the group of related items
14953 * @param {object} config configuration attributes
14955 init: function(id, sGroup, config) {
14956 this.initTarget(id, sGroup, config);
14957 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14958 // Event.on(this.id, "selectstart", Event.preventDefault);
14962 * Initializes Targeting functionality only... the object does not
14963 * get a mousedown handler.
14964 * @method initTarget
14965 * @param id the id of the linked element
14966 * @param {String} sGroup the group of related items
14967 * @param {object} config configuration attributes
14969 initTarget: function(id, sGroup, config) {
14971 // configuration attributes
14972 this.config = config || {};
14974 // create a local reference to the drag and drop manager
14975 this.DDM = Roo.dd.DDM;
14976 // initialize the groups array
14979 // assume that we have an element reference instead of an id if the
14980 // parameter is not a string
14981 if (typeof id !== "string") {
14988 // add to an interaction group
14989 this.addToGroup((sGroup) ? sGroup : "default");
14991 // We don't want to register this as the handle with the manager
14992 // so we just set the id rather than calling the setter.
14993 this.handleElId = id;
14995 // the linked element is the element that gets dragged by default
14996 this.setDragElId(id);
14998 // by default, clicked anchors will not start drag operations.
14999 this.invalidHandleTypes = { A: "A" };
15000 this.invalidHandleIds = {};
15001 this.invalidHandleClasses = [];
15003 this.applyConfig();
15005 this.handleOnAvailable();
15009 * Applies the configuration parameters that were passed into the constructor.
15010 * This is supposed to happen at each level through the inheritance chain. So
15011 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15012 * DragDrop in order to get all of the parameters that are available in
15014 * @method applyConfig
15016 applyConfig: function() {
15018 // configurable properties:
15019 // padding, isTarget, maintainOffset, primaryButtonOnly
15020 this.padding = this.config.padding || [0, 0, 0, 0];
15021 this.isTarget = (this.config.isTarget !== false);
15022 this.maintainOffset = (this.config.maintainOffset);
15023 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15028 * Executed when the linked element is available
15029 * @method handleOnAvailable
15032 handleOnAvailable: function() {
15033 this.available = true;
15034 this.resetConstraints();
15035 this.onAvailable();
15039 * Configures the padding for the target zone in px. Effectively expands
15040 * (or reduces) the virtual object size for targeting calculations.
15041 * Supports css-style shorthand; if only one parameter is passed, all sides
15042 * will have that padding, and if only two are passed, the top and bottom
15043 * will have the first param, the left and right the second.
15044 * @method setPadding
15045 * @param {int} iTop Top pad
15046 * @param {int} iRight Right pad
15047 * @param {int} iBot Bot pad
15048 * @param {int} iLeft Left pad
15050 setPadding: function(iTop, iRight, iBot, iLeft) {
15051 // this.padding = [iLeft, iRight, iTop, iBot];
15052 if (!iRight && 0 !== iRight) {
15053 this.padding = [iTop, iTop, iTop, iTop];
15054 } else if (!iBot && 0 !== iBot) {
15055 this.padding = [iTop, iRight, iTop, iRight];
15057 this.padding = [iTop, iRight, iBot, iLeft];
15062 * Stores the initial placement of the linked element.
15063 * @method setInitialPosition
15064 * @param {int} diffX the X offset, default 0
15065 * @param {int} diffY the Y offset, default 0
15067 setInitPosition: function(diffX, diffY) {
15068 var el = this.getEl();
15070 if (!this.DDM.verifyEl(el)) {
15074 var dx = diffX || 0;
15075 var dy = diffY || 0;
15077 var p = Dom.getXY( el );
15079 this.initPageX = p[0] - dx;
15080 this.initPageY = p[1] - dy;
15082 this.lastPageX = p[0];
15083 this.lastPageY = p[1];
15086 this.setStartPosition(p);
15090 * Sets the start position of the element. This is set when the obj
15091 * is initialized, the reset when a drag is started.
15092 * @method setStartPosition
15093 * @param pos current position (from previous lookup)
15096 setStartPosition: function(pos) {
15097 var p = pos || Dom.getXY( this.getEl() );
15098 this.deltaSetXY = null;
15100 this.startPageX = p[0];
15101 this.startPageY = p[1];
15105 * Add this instance to a group of related drag/drop objects. All
15106 * instances belong to at least one group, and can belong to as many
15107 * groups as needed.
15108 * @method addToGroup
15109 * @param sGroup {string} the name of the group
15111 addToGroup: function(sGroup) {
15112 this.groups[sGroup] = true;
15113 this.DDM.regDragDrop(this, sGroup);
15117 * Remove's this instance from the supplied interaction group
15118 * @method removeFromGroup
15119 * @param {string} sGroup The group to drop
15121 removeFromGroup: function(sGroup) {
15122 if (this.groups[sGroup]) {
15123 delete this.groups[sGroup];
15126 this.DDM.removeDDFromGroup(this, sGroup);
15130 * Allows you to specify that an element other than the linked element
15131 * will be moved with the cursor during a drag
15132 * @method setDragElId
15133 * @param id {string} the id of the element that will be used to initiate the drag
15135 setDragElId: function(id) {
15136 this.dragElId = id;
15140 * Allows you to specify a child of the linked element that should be
15141 * used to initiate the drag operation. An example of this would be if
15142 * you have a content div with text and links. Clicking anywhere in the
15143 * content area would normally start the drag operation. Use this method
15144 * to specify that an element inside of the content div is the element
15145 * that starts the drag operation.
15146 * @method setHandleElId
15147 * @param id {string} the id of the element that will be used to
15148 * initiate the drag.
15150 setHandleElId: function(id) {
15151 if (typeof id !== "string") {
15154 this.handleElId = id;
15155 this.DDM.regHandle(this.id, id);
15159 * Allows you to set an element outside of the linked element as a drag
15161 * @method setOuterHandleElId
15162 * @param id the id of the element that will be used to initiate the drag
15164 setOuterHandleElId: function(id) {
15165 if (typeof id !== "string") {
15168 Event.on(id, "mousedown",
15169 this.handleMouseDown, this);
15170 this.setHandleElId(id);
15172 this.hasOuterHandles = true;
15176 * Remove all drag and drop hooks for this element
15179 unreg: function() {
15180 Event.un(this.id, "mousedown",
15181 this.handleMouseDown);
15182 this._domRef = null;
15183 this.DDM._remove(this);
15186 destroy : function(){
15191 * Returns true if this instance is locked, or the drag drop mgr is locked
15192 * (meaning that all drag/drop is disabled on the page.)
15194 * @return {boolean} true if this obj or all drag/drop is locked, else
15197 isLocked: function() {
15198 return (this.DDM.isLocked() || this.locked);
15202 * Fired when this object is clicked
15203 * @method handleMouseDown
15205 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15208 handleMouseDown: function(e, oDD){
15209 if (this.primaryButtonOnly && e.button != 0) {
15213 if (this.isLocked()) {
15217 this.DDM.refreshCache(this.groups);
15219 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15220 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15222 if (this.clickValidator(e)) {
15224 // set the initial element position
15225 this.setStartPosition();
15228 this.b4MouseDown(e);
15229 this.onMouseDown(e);
15231 this.DDM.handleMouseDown(e, this);
15233 this.DDM.stopEvent(e);
15241 clickValidator: function(e) {
15242 var target = e.getTarget();
15243 return ( this.isValidHandleChild(target) &&
15244 (this.id == this.handleElId ||
15245 this.DDM.handleWasClicked(target, this.id)) );
15249 * Allows you to specify a tag name that should not start a drag operation
15250 * when clicked. This is designed to facilitate embedding links within a
15251 * drag handle that do something other than start the drag.
15252 * @method addInvalidHandleType
15253 * @param {string} tagName the type of element to exclude
15255 addInvalidHandleType: function(tagName) {
15256 var type = tagName.toUpperCase();
15257 this.invalidHandleTypes[type] = type;
15261 * Lets you to specify an element id for a child of a drag handle
15262 * that should not initiate a drag
15263 * @method addInvalidHandleId
15264 * @param {string} id the element id of the element you wish to ignore
15266 addInvalidHandleId: function(id) {
15267 if (typeof id !== "string") {
15270 this.invalidHandleIds[id] = id;
15274 * Lets you specify a css class of elements that will not initiate a drag
15275 * @method addInvalidHandleClass
15276 * @param {string} cssClass the class of the elements you wish to ignore
15278 addInvalidHandleClass: function(cssClass) {
15279 this.invalidHandleClasses.push(cssClass);
15283 * Unsets an excluded tag name set by addInvalidHandleType
15284 * @method removeInvalidHandleType
15285 * @param {string} tagName the type of element to unexclude
15287 removeInvalidHandleType: function(tagName) {
15288 var type = tagName.toUpperCase();
15289 // this.invalidHandleTypes[type] = null;
15290 delete this.invalidHandleTypes[type];
15294 * Unsets an invalid handle id
15295 * @method removeInvalidHandleId
15296 * @param {string} id the id of the element to re-enable
15298 removeInvalidHandleId: function(id) {
15299 if (typeof id !== "string") {
15302 delete this.invalidHandleIds[id];
15306 * Unsets an invalid css class
15307 * @method removeInvalidHandleClass
15308 * @param {string} cssClass the class of the element(s) you wish to
15311 removeInvalidHandleClass: function(cssClass) {
15312 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15313 if (this.invalidHandleClasses[i] == cssClass) {
15314 delete this.invalidHandleClasses[i];
15320 * Checks the tag exclusion list to see if this click should be ignored
15321 * @method isValidHandleChild
15322 * @param {HTMLElement} node the HTMLElement to evaluate
15323 * @return {boolean} true if this is a valid tag type, false if not
15325 isValidHandleChild: function(node) {
15328 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15331 nodeName = node.nodeName.toUpperCase();
15333 nodeName = node.nodeName;
15335 valid = valid && !this.invalidHandleTypes[nodeName];
15336 valid = valid && !this.invalidHandleIds[node.id];
15338 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15339 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15348 * Create the array of horizontal tick marks if an interval was specified
15349 * in setXConstraint().
15350 * @method setXTicks
15353 setXTicks: function(iStartX, iTickSize) {
15355 this.xTickSize = iTickSize;
15359 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15361 this.xTicks[this.xTicks.length] = i;
15366 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15368 this.xTicks[this.xTicks.length] = i;
15373 this.xTicks.sort(this.DDM.numericSort) ;
15377 * Create the array of vertical tick marks if an interval was specified in
15378 * setYConstraint().
15379 * @method setYTicks
15382 setYTicks: function(iStartY, iTickSize) {
15384 this.yTickSize = iTickSize;
15388 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15390 this.yTicks[this.yTicks.length] = i;
15395 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15397 this.yTicks[this.yTicks.length] = i;
15402 this.yTicks.sort(this.DDM.numericSort) ;
15406 * By default, the element can be dragged any place on the screen. Use
15407 * this method to limit the horizontal travel of the element. Pass in
15408 * 0,0 for the parameters if you want to lock the drag to the y axis.
15409 * @method setXConstraint
15410 * @param {int} iLeft the number of pixels the element can move to the left
15411 * @param {int} iRight the number of pixels the element can move to the
15413 * @param {int} iTickSize optional parameter for specifying that the
15415 * should move iTickSize pixels at a time.
15417 setXConstraint: function(iLeft, iRight, iTickSize) {
15418 this.leftConstraint = iLeft;
15419 this.rightConstraint = iRight;
15421 this.minX = this.initPageX - iLeft;
15422 this.maxX = this.initPageX + iRight;
15423 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15425 this.constrainX = true;
15429 * Clears any constraints applied to this instance. Also clears ticks
15430 * since they can't exist independent of a constraint at this time.
15431 * @method clearConstraints
15433 clearConstraints: function() {
15434 this.constrainX = false;
15435 this.constrainY = false;
15440 * Clears any tick interval defined for this instance
15441 * @method clearTicks
15443 clearTicks: function() {
15444 this.xTicks = null;
15445 this.yTicks = null;
15446 this.xTickSize = 0;
15447 this.yTickSize = 0;
15451 * By default, the element can be dragged any place on the screen. Set
15452 * this to limit the vertical travel of the element. Pass in 0,0 for the
15453 * parameters if you want to lock the drag to the x axis.
15454 * @method setYConstraint
15455 * @param {int} iUp the number of pixels the element can move up
15456 * @param {int} iDown the number of pixels the element can move down
15457 * @param {int} iTickSize optional parameter for specifying that the
15458 * element should move iTickSize pixels at a time.
15460 setYConstraint: function(iUp, iDown, iTickSize) {
15461 this.topConstraint = iUp;
15462 this.bottomConstraint = iDown;
15464 this.minY = this.initPageY - iUp;
15465 this.maxY = this.initPageY + iDown;
15466 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15468 this.constrainY = true;
15473 * resetConstraints must be called if you manually reposition a dd element.
15474 * @method resetConstraints
15475 * @param {boolean} maintainOffset
15477 resetConstraints: function() {
15480 // Maintain offsets if necessary
15481 if (this.initPageX || this.initPageX === 0) {
15482 // figure out how much this thing has moved
15483 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15484 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15486 this.setInitPosition(dx, dy);
15488 // This is the first time we have detected the element's position
15490 this.setInitPosition();
15493 if (this.constrainX) {
15494 this.setXConstraint( this.leftConstraint,
15495 this.rightConstraint,
15499 if (this.constrainY) {
15500 this.setYConstraint( this.topConstraint,
15501 this.bottomConstraint,
15507 * Normally the drag element is moved pixel by pixel, but we can specify
15508 * that it move a number of pixels at a time. This method resolves the
15509 * location when we have it set up like this.
15511 * @param {int} val where we want to place the object
15512 * @param {int[]} tickArray sorted array of valid points
15513 * @return {int} the closest tick
15516 getTick: function(val, tickArray) {
15519 // If tick interval is not defined, it is effectively 1 pixel,
15520 // so we return the value passed to us.
15522 } else if (tickArray[0] >= val) {
15523 // The value is lower than the first tick, so we return the first
15525 return tickArray[0];
15527 for (var i=0, len=tickArray.length; i<len; ++i) {
15529 if (tickArray[next] && tickArray[next] >= val) {
15530 var diff1 = val - tickArray[i];
15531 var diff2 = tickArray[next] - val;
15532 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15536 // The value is larger than the last tick, so we return the last
15538 return tickArray[tickArray.length - 1];
15545 * @return {string} string representation of the dd obj
15547 toString: function() {
15548 return ("DragDrop " + this.id);
15556 * Ext JS Library 1.1.1
15557 * Copyright(c) 2006-2007, Ext JS, LLC.
15559 * Originally Released Under LGPL - original licence link has changed is not relivant.
15562 * <script type="text/javascript">
15567 * The drag and drop utility provides a framework for building drag and drop
15568 * applications. In addition to enabling drag and drop for specific elements,
15569 * the drag and drop elements are tracked by the manager class, and the
15570 * interactions between the various elements are tracked during the drag and
15571 * the implementing code is notified about these important moments.
15574 // Only load the library once. Rewriting the manager class would orphan
15575 // existing drag and drop instances.
15576 if (!Roo.dd.DragDropMgr) {
15579 * @class Roo.dd.DragDropMgr
15580 * DragDropMgr is a singleton that tracks the element interaction for
15581 * all DragDrop items in the window. Generally, you will not call
15582 * this class directly, but it does have helper methods that could
15583 * be useful in your DragDrop implementations.
15586 Roo.dd.DragDropMgr = function() {
15588 var Event = Roo.EventManager;
15593 * Two dimensional Array of registered DragDrop objects. The first
15594 * dimension is the DragDrop item group, the second the DragDrop
15597 * @type {string: string}
15604 * Array of element ids defined as drag handles. Used to determine
15605 * if the element that generated the mousedown event is actually the
15606 * handle and not the html element itself.
15607 * @property handleIds
15608 * @type {string: string}
15615 * the DragDrop object that is currently being dragged
15616 * @property dragCurrent
15624 * the DragDrop object(s) that are being hovered over
15625 * @property dragOvers
15633 * the X distance between the cursor and the object being dragged
15642 * the Y distance between the cursor and the object being dragged
15651 * Flag to determine if we should prevent the default behavior of the
15652 * events we define. By default this is true, but this can be set to
15653 * false if you need the default behavior (not recommended)
15654 * @property preventDefault
15658 preventDefault: true,
15661 * Flag to determine if we should stop the propagation of the events
15662 * we generate. This is true by default but you may want to set it to
15663 * false if the html element contains other features that require the
15665 * @property stopPropagation
15669 stopPropagation: true,
15672 * Internal flag that is set to true when drag and drop has been
15674 * @property initialized
15681 * All drag and drop can be disabled.
15689 * Called the first time an element is registered.
15695 this.initialized = true;
15699 * In point mode, drag and drop interaction is defined by the
15700 * location of the cursor during the drag/drop
15708 * In intersect mode, drag and drop interactio nis defined by the
15709 * overlap of two or more drag and drop objects.
15710 * @property INTERSECT
15717 * The current drag and drop mode. Default: POINT
15725 * Runs method on all drag and drop objects
15726 * @method _execOnAll
15730 _execOnAll: function(sMethod, args) {
15731 for (var i in this.ids) {
15732 for (var j in this.ids[i]) {
15733 var oDD = this.ids[i][j];
15734 if (! this.isTypeOfDD(oDD)) {
15737 oDD[sMethod].apply(oDD, args);
15743 * Drag and drop initialization. Sets up the global event handlers
15748 _onLoad: function() {
15753 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15754 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15755 Event.on(window, "unload", this._onUnload, this, true);
15756 Event.on(window, "resize", this._onResize, this, true);
15757 // Event.on(window, "mouseout", this._test);
15762 * Reset constraints on all drag and drop objs
15763 * @method _onResize
15767 _onResize: function(e) {
15768 this._execOnAll("resetConstraints", []);
15772 * Lock all drag and drop functionality
15776 lock: function() { this.locked = true; },
15779 * Unlock all drag and drop functionality
15783 unlock: function() { this.locked = false; },
15786 * Is drag and drop locked?
15788 * @return {boolean} True if drag and drop is locked, false otherwise.
15791 isLocked: function() { return this.locked; },
15794 * Location cache that is set for all drag drop objects when a drag is
15795 * initiated, cleared when the drag is finished.
15796 * @property locationCache
15803 * Set useCache to false if you want to force object the lookup of each
15804 * drag and drop linked element constantly during a drag.
15805 * @property useCache
15812 * The number of pixels that the mouse needs to move after the
15813 * mousedown before the drag is initiated. Default=3;
15814 * @property clickPixelThresh
15818 clickPixelThresh: 3,
15821 * The number of milliseconds after the mousedown event to initiate the
15822 * drag if we don't get a mouseup event. Default=1000
15823 * @property clickTimeThresh
15827 clickTimeThresh: 350,
15830 * Flag that indicates that either the drag pixel threshold or the
15831 * mousdown time threshold has been met
15832 * @property dragThreshMet
15837 dragThreshMet: false,
15840 * Timeout used for the click time threshold
15841 * @property clickTimeout
15846 clickTimeout: null,
15849 * The X position of the mousedown event stored for later use when a
15850 * drag threshold is met.
15859 * The Y position of the mousedown event stored for later use when a
15860 * drag threshold is met.
15869 * Each DragDrop instance must be registered with the DragDropMgr.
15870 * This is executed in DragDrop.init()
15871 * @method regDragDrop
15872 * @param {DragDrop} oDD the DragDrop object to register
15873 * @param {String} sGroup the name of the group this element belongs to
15876 regDragDrop: function(oDD, sGroup) {
15877 if (!this.initialized) { this.init(); }
15879 if (!this.ids[sGroup]) {
15880 this.ids[sGroup] = {};
15882 this.ids[sGroup][oDD.id] = oDD;
15886 * Removes the supplied dd instance from the supplied group. Executed
15887 * by DragDrop.removeFromGroup, so don't call this function directly.
15888 * @method removeDDFromGroup
15892 removeDDFromGroup: function(oDD, sGroup) {
15893 if (!this.ids[sGroup]) {
15894 this.ids[sGroup] = {};
15897 var obj = this.ids[sGroup];
15898 if (obj && obj[oDD.id]) {
15899 delete obj[oDD.id];
15904 * Unregisters a drag and drop item. This is executed in
15905 * DragDrop.unreg, use that method instead of calling this directly.
15910 _remove: function(oDD) {
15911 for (var g in oDD.groups) {
15912 if (g && this.ids[g][oDD.id]) {
15913 delete this.ids[g][oDD.id];
15916 delete this.handleIds[oDD.id];
15920 * Each DragDrop handle element must be registered. This is done
15921 * automatically when executing DragDrop.setHandleElId()
15922 * @method regHandle
15923 * @param {String} sDDId the DragDrop id this element is a handle for
15924 * @param {String} sHandleId the id of the element that is the drag
15928 regHandle: function(sDDId, sHandleId) {
15929 if (!this.handleIds[sDDId]) {
15930 this.handleIds[sDDId] = {};
15932 this.handleIds[sDDId][sHandleId] = sHandleId;
15936 * Utility function to determine if a given element has been
15937 * registered as a drag drop item.
15938 * @method isDragDrop
15939 * @param {String} id the element id to check
15940 * @return {boolean} true if this element is a DragDrop item,
15944 isDragDrop: function(id) {
15945 return ( this.getDDById(id) ) ? true : false;
15949 * Returns the drag and drop instances that are in all groups the
15950 * passed in instance belongs to.
15951 * @method getRelated
15952 * @param {DragDrop} p_oDD the obj to get related data for
15953 * @param {boolean} bTargetsOnly if true, only return targetable objs
15954 * @return {DragDrop[]} the related instances
15957 getRelated: function(p_oDD, bTargetsOnly) {
15959 for (var i in p_oDD.groups) {
15960 for (j in this.ids[i]) {
15961 var dd = this.ids[i][j];
15962 if (! this.isTypeOfDD(dd)) {
15965 if (!bTargetsOnly || dd.isTarget) {
15966 oDDs[oDDs.length] = dd;
15975 * Returns true if the specified dd target is a legal target for
15976 * the specifice drag obj
15977 * @method isLegalTarget
15978 * @param {DragDrop} the drag obj
15979 * @param {DragDrop} the target
15980 * @return {boolean} true if the target is a legal target for the
15984 isLegalTarget: function (oDD, oTargetDD) {
15985 var targets = this.getRelated(oDD, true);
15986 for (var i=0, len=targets.length;i<len;++i) {
15987 if (targets[i].id == oTargetDD.id) {
15996 * My goal is to be able to transparently determine if an object is
15997 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15998 * returns "object", oDD.constructor.toString() always returns
15999 * "DragDrop" and not the name of the subclass. So for now it just
16000 * evaluates a well-known variable in DragDrop.
16001 * @method isTypeOfDD
16002 * @param {Object} the object to evaluate
16003 * @return {boolean} true if typeof oDD = DragDrop
16006 isTypeOfDD: function (oDD) {
16007 return (oDD && oDD.__ygDragDrop);
16011 * Utility function to determine if a given element has been
16012 * registered as a drag drop handle for the given Drag Drop object.
16014 * @param {String} id the element id to check
16015 * @return {boolean} true if this element is a DragDrop handle, false
16019 isHandle: function(sDDId, sHandleId) {
16020 return ( this.handleIds[sDDId] &&
16021 this.handleIds[sDDId][sHandleId] );
16025 * Returns the DragDrop instance for a given id
16026 * @method getDDById
16027 * @param {String} id the id of the DragDrop object
16028 * @return {DragDrop} the drag drop object, null if it is not found
16031 getDDById: function(id) {
16032 for (var i in this.ids) {
16033 if (this.ids[i][id]) {
16034 return this.ids[i][id];
16041 * Fired after a registered DragDrop object gets the mousedown event.
16042 * Sets up the events required to track the object being dragged
16043 * @method handleMouseDown
16044 * @param {Event} e the event
16045 * @param oDD the DragDrop object being dragged
16049 handleMouseDown: function(e, oDD) {
16051 Roo.QuickTips.disable();
16053 this.currentTarget = e.getTarget();
16055 this.dragCurrent = oDD;
16057 var el = oDD.getEl();
16059 // track start position
16060 this.startX = e.getPageX();
16061 this.startY = e.getPageY();
16063 this.deltaX = this.startX - el.offsetLeft;
16064 this.deltaY = this.startY - el.offsetTop;
16066 this.dragThreshMet = false;
16068 this.clickTimeout = setTimeout(
16070 var DDM = Roo.dd.DDM;
16071 DDM.startDrag(DDM.startX, DDM.startY);
16073 this.clickTimeThresh );
16077 * Fired when either the drag pixel threshol or the mousedown hold
16078 * time threshold has been met.
16079 * @method startDrag
16080 * @param x {int} the X position of the original mousedown
16081 * @param y {int} the Y position of the original mousedown
16084 startDrag: function(x, y) {
16085 clearTimeout(this.clickTimeout);
16086 if (this.dragCurrent) {
16087 this.dragCurrent.b4StartDrag(x, y);
16088 this.dragCurrent.startDrag(x, y);
16090 this.dragThreshMet = true;
16094 * Internal function to handle the mouseup event. Will be invoked
16095 * from the context of the document.
16096 * @method handleMouseUp
16097 * @param {Event} e the event
16101 handleMouseUp: function(e) {
16104 Roo.QuickTips.enable();
16106 if (! this.dragCurrent) {
16110 clearTimeout(this.clickTimeout);
16112 if (this.dragThreshMet) {
16113 this.fireEvents(e, true);
16123 * Utility to stop event propagation and event default, if these
16124 * features are turned on.
16125 * @method stopEvent
16126 * @param {Event} e the event as returned by this.getEvent()
16129 stopEvent: function(e){
16130 if(this.stopPropagation) {
16131 e.stopPropagation();
16134 if (this.preventDefault) {
16135 e.preventDefault();
16140 * Internal function to clean up event handlers after the drag
16141 * operation is complete
16143 * @param {Event} e the event
16147 stopDrag: function(e) {
16148 // Fire the drag end event for the item that was dragged
16149 if (this.dragCurrent) {
16150 if (this.dragThreshMet) {
16151 this.dragCurrent.b4EndDrag(e);
16152 this.dragCurrent.endDrag(e);
16155 this.dragCurrent.onMouseUp(e);
16158 this.dragCurrent = null;
16159 this.dragOvers = {};
16163 * Internal function to handle the mousemove event. Will be invoked
16164 * from the context of the html element.
16166 * @TODO figure out what we can do about mouse events lost when the
16167 * user drags objects beyond the window boundary. Currently we can
16168 * detect this in internet explorer by verifying that the mouse is
16169 * down during the mousemove event. Firefox doesn't give us the
16170 * button state on the mousemove event.
16171 * @method handleMouseMove
16172 * @param {Event} e the event
16176 handleMouseMove: function(e) {
16177 if (! this.dragCurrent) {
16181 // var button = e.which || e.button;
16183 // check for IE mouseup outside of page boundary
16184 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16186 return this.handleMouseUp(e);
16189 if (!this.dragThreshMet) {
16190 var diffX = Math.abs(this.startX - e.getPageX());
16191 var diffY = Math.abs(this.startY - e.getPageY());
16192 if (diffX > this.clickPixelThresh ||
16193 diffY > this.clickPixelThresh) {
16194 this.startDrag(this.startX, this.startY);
16198 if (this.dragThreshMet) {
16199 this.dragCurrent.b4Drag(e);
16200 this.dragCurrent.onDrag(e);
16201 if(!this.dragCurrent.moveOnly){
16202 this.fireEvents(e, false);
16212 * Iterates over all of the DragDrop elements to find ones we are
16213 * hovering over or dropping on
16214 * @method fireEvents
16215 * @param {Event} e the event
16216 * @param {boolean} isDrop is this a drop op or a mouseover op?
16220 fireEvents: function(e, isDrop) {
16221 var dc = this.dragCurrent;
16223 // If the user did the mouse up outside of the window, we could
16224 // get here even though we have ended the drag.
16225 if (!dc || dc.isLocked()) {
16229 var pt = e.getPoint();
16231 // cache the previous dragOver array
16237 var enterEvts = [];
16239 // Check to see if the object(s) we were hovering over is no longer
16240 // being hovered over so we can fire the onDragOut event
16241 for (var i in this.dragOvers) {
16243 var ddo = this.dragOvers[i];
16245 if (! this.isTypeOfDD(ddo)) {
16249 if (! this.isOverTarget(pt, ddo, this.mode)) {
16250 outEvts.push( ddo );
16253 oldOvers[i] = true;
16254 delete this.dragOvers[i];
16257 for (var sGroup in dc.groups) {
16259 if ("string" != typeof sGroup) {
16263 for (i in this.ids[sGroup]) {
16264 var oDD = this.ids[sGroup][i];
16265 if (! this.isTypeOfDD(oDD)) {
16269 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16270 if (this.isOverTarget(pt, oDD, this.mode)) {
16271 // look for drop interactions
16273 dropEvts.push( oDD );
16274 // look for drag enter and drag over interactions
16277 // initial drag over: dragEnter fires
16278 if (!oldOvers[oDD.id]) {
16279 enterEvts.push( oDD );
16280 // subsequent drag overs: dragOver fires
16282 overEvts.push( oDD );
16285 this.dragOvers[oDD.id] = oDD;
16293 if (outEvts.length) {
16294 dc.b4DragOut(e, outEvts);
16295 dc.onDragOut(e, outEvts);
16298 if (enterEvts.length) {
16299 dc.onDragEnter(e, enterEvts);
16302 if (overEvts.length) {
16303 dc.b4DragOver(e, overEvts);
16304 dc.onDragOver(e, overEvts);
16307 if (dropEvts.length) {
16308 dc.b4DragDrop(e, dropEvts);
16309 dc.onDragDrop(e, dropEvts);
16313 // fire dragout events
16315 for (i=0, len=outEvts.length; i<len; ++i) {
16316 dc.b4DragOut(e, outEvts[i].id);
16317 dc.onDragOut(e, outEvts[i].id);
16320 // fire enter events
16321 for (i=0,len=enterEvts.length; i<len; ++i) {
16322 // dc.b4DragEnter(e, oDD.id);
16323 dc.onDragEnter(e, enterEvts[i].id);
16326 // fire over events
16327 for (i=0,len=overEvts.length; i<len; ++i) {
16328 dc.b4DragOver(e, overEvts[i].id);
16329 dc.onDragOver(e, overEvts[i].id);
16332 // fire drop events
16333 for (i=0, len=dropEvts.length; i<len; ++i) {
16334 dc.b4DragDrop(e, dropEvts[i].id);
16335 dc.onDragDrop(e, dropEvts[i].id);
16340 // notify about a drop that did not find a target
16341 if (isDrop && !dropEvts.length) {
16342 dc.onInvalidDrop(e);
16348 * Helper function for getting the best match from the list of drag
16349 * and drop objects returned by the drag and drop events when we are
16350 * in INTERSECT mode. It returns either the first object that the
16351 * cursor is over, or the object that has the greatest overlap with
16352 * the dragged element.
16353 * @method getBestMatch
16354 * @param {DragDrop[]} dds The array of drag and drop objects
16356 * @return {DragDrop} The best single match
16359 getBestMatch: function(dds) {
16361 // Return null if the input is not what we expect
16362 //if (!dds || !dds.length || dds.length == 0) {
16364 // If there is only one item, it wins
16365 //} else if (dds.length == 1) {
16367 var len = dds.length;
16372 // Loop through the targeted items
16373 for (var i=0; i<len; ++i) {
16375 // If the cursor is over the object, it wins. If the
16376 // cursor is over multiple matches, the first one we come
16378 if (dd.cursorIsOver) {
16381 // Otherwise the object with the most overlap wins
16384 winner.overlap.getArea() < dd.overlap.getArea()) {
16395 * Refreshes the cache of the top-left and bottom-right points of the
16396 * drag and drop objects in the specified group(s). This is in the
16397 * format that is stored in the drag and drop instance, so typical
16400 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16404 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16406 * @TODO this really should be an indexed array. Alternatively this
16407 * method could accept both.
16408 * @method refreshCache
16409 * @param {Object} groups an associative array of groups to refresh
16412 refreshCache: function(groups) {
16413 for (var sGroup in groups) {
16414 if ("string" != typeof sGroup) {
16417 for (var i in this.ids[sGroup]) {
16418 var oDD = this.ids[sGroup][i];
16420 if (this.isTypeOfDD(oDD)) {
16421 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16422 var loc = this.getLocation(oDD);
16424 this.locationCache[oDD.id] = loc;
16426 delete this.locationCache[oDD.id];
16427 // this will unregister the drag and drop object if
16428 // the element is not in a usable state
16437 * This checks to make sure an element exists and is in the DOM. The
16438 * main purpose is to handle cases where innerHTML is used to remove
16439 * drag and drop objects from the DOM. IE provides an 'unspecified
16440 * error' when trying to access the offsetParent of such an element
16442 * @param {HTMLElement} el the element to check
16443 * @return {boolean} true if the element looks usable
16446 verifyEl: function(el) {
16451 parent = el.offsetParent;
16454 parent = el.offsetParent;
16465 * Returns a Region object containing the drag and drop element's position
16466 * and size, including the padding configured for it
16467 * @method getLocation
16468 * @param {DragDrop} oDD the drag and drop object to get the
16470 * @return {Roo.lib.Region} a Region object representing the total area
16471 * the element occupies, including any padding
16472 * the instance is configured for.
16475 getLocation: function(oDD) {
16476 if (! this.isTypeOfDD(oDD)) {
16480 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16483 pos= Roo.lib.Dom.getXY(el);
16491 x2 = x1 + el.offsetWidth;
16493 y2 = y1 + el.offsetHeight;
16495 t = y1 - oDD.padding[0];
16496 r = x2 + oDD.padding[1];
16497 b = y2 + oDD.padding[2];
16498 l = x1 - oDD.padding[3];
16500 return new Roo.lib.Region( t, r, b, l );
16504 * Checks the cursor location to see if it over the target
16505 * @method isOverTarget
16506 * @param {Roo.lib.Point} pt The point to evaluate
16507 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16508 * @return {boolean} true if the mouse is over the target
16512 isOverTarget: function(pt, oTarget, intersect) {
16513 // use cache if available
16514 var loc = this.locationCache[oTarget.id];
16515 if (!loc || !this.useCache) {
16516 loc = this.getLocation(oTarget);
16517 this.locationCache[oTarget.id] = loc;
16525 oTarget.cursorIsOver = loc.contains( pt );
16527 // DragDrop is using this as a sanity check for the initial mousedown
16528 // in this case we are done. In POINT mode, if the drag obj has no
16529 // contraints, we are also done. Otherwise we need to evaluate the
16530 // location of the target as related to the actual location of the
16531 // dragged element.
16532 var dc = this.dragCurrent;
16533 if (!dc || !dc.getTargetCoord ||
16534 (!intersect && !dc.constrainX && !dc.constrainY)) {
16535 return oTarget.cursorIsOver;
16538 oTarget.overlap = null;
16540 // Get the current location of the drag element, this is the
16541 // location of the mouse event less the delta that represents
16542 // where the original mousedown happened on the element. We
16543 // need to consider constraints and ticks as well.
16544 var pos = dc.getTargetCoord(pt.x, pt.y);
16546 var el = dc.getDragEl();
16547 var curRegion = new Roo.lib.Region( pos.y,
16548 pos.x + el.offsetWidth,
16549 pos.y + el.offsetHeight,
16552 var overlap = curRegion.intersect(loc);
16555 oTarget.overlap = overlap;
16556 return (intersect) ? true : oTarget.cursorIsOver;
16563 * unload event handler
16564 * @method _onUnload
16568 _onUnload: function(e, me) {
16569 Roo.dd.DragDropMgr.unregAll();
16573 * Cleans up the drag and drop events and objects.
16578 unregAll: function() {
16580 if (this.dragCurrent) {
16582 this.dragCurrent = null;
16585 this._execOnAll("unreg", []);
16587 for (i in this.elementCache) {
16588 delete this.elementCache[i];
16591 this.elementCache = {};
16596 * A cache of DOM elements
16597 * @property elementCache
16604 * Get the wrapper for the DOM element specified
16605 * @method getElWrapper
16606 * @param {String} id the id of the element to get
16607 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16609 * @deprecated This wrapper isn't that useful
16612 getElWrapper: function(id) {
16613 var oWrapper = this.elementCache[id];
16614 if (!oWrapper || !oWrapper.el) {
16615 oWrapper = this.elementCache[id] =
16616 new this.ElementWrapper(Roo.getDom(id));
16622 * Returns the actual DOM element
16623 * @method getElement
16624 * @param {String} id the id of the elment to get
16625 * @return {Object} The element
16626 * @deprecated use Roo.getDom instead
16629 getElement: function(id) {
16630 return Roo.getDom(id);
16634 * Returns the style property for the DOM element (i.e.,
16635 * document.getElById(id).style)
16637 * @param {String} id the id of the elment to get
16638 * @return {Object} The style property of the element
16639 * @deprecated use Roo.getDom instead
16642 getCss: function(id) {
16643 var el = Roo.getDom(id);
16644 return (el) ? el.style : null;
16648 * Inner class for cached elements
16649 * @class DragDropMgr.ElementWrapper
16654 ElementWrapper: function(el) {
16659 this.el = el || null;
16664 this.id = this.el && el.id;
16666 * A reference to the style property
16669 this.css = this.el && el.style;
16673 * Returns the X position of an html element
16675 * @param el the element for which to get the position
16676 * @return {int} the X coordinate
16678 * @deprecated use Roo.lib.Dom.getX instead
16681 getPosX: function(el) {
16682 return Roo.lib.Dom.getX(el);
16686 * Returns the Y position of an html element
16688 * @param el the element for which to get the position
16689 * @return {int} the Y coordinate
16690 * @deprecated use Roo.lib.Dom.getY instead
16693 getPosY: function(el) {
16694 return Roo.lib.Dom.getY(el);
16698 * Swap two nodes. In IE, we use the native method, for others we
16699 * emulate the IE behavior
16701 * @param n1 the first node to swap
16702 * @param n2 the other node to swap
16705 swapNode: function(n1, n2) {
16709 var p = n2.parentNode;
16710 var s = n2.nextSibling;
16713 p.insertBefore(n1, n2);
16714 } else if (n2 == n1.nextSibling) {
16715 p.insertBefore(n2, n1);
16717 n1.parentNode.replaceChild(n2, n1);
16718 p.insertBefore(n1, s);
16724 * Returns the current scroll position
16725 * @method getScroll
16729 getScroll: function () {
16730 var t, l, dde=document.documentElement, db=document.body;
16731 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16733 l = dde.scrollLeft;
16740 return { top: t, left: l };
16744 * Returns the specified element style property
16746 * @param {HTMLElement} el the element
16747 * @param {string} styleProp the style property
16748 * @return {string} The value of the style property
16749 * @deprecated use Roo.lib.Dom.getStyle
16752 getStyle: function(el, styleProp) {
16753 return Roo.fly(el).getStyle(styleProp);
16757 * Gets the scrollTop
16758 * @method getScrollTop
16759 * @return {int} the document's scrollTop
16762 getScrollTop: function () { return this.getScroll().top; },
16765 * Gets the scrollLeft
16766 * @method getScrollLeft
16767 * @return {int} the document's scrollTop
16770 getScrollLeft: function () { return this.getScroll().left; },
16773 * Sets the x/y position of an element to the location of the
16776 * @param {HTMLElement} moveEl The element to move
16777 * @param {HTMLElement} targetEl The position reference element
16780 moveToEl: function (moveEl, targetEl) {
16781 var aCoord = Roo.lib.Dom.getXY(targetEl);
16782 Roo.lib.Dom.setXY(moveEl, aCoord);
16786 * Numeric array sort function
16787 * @method numericSort
16790 numericSort: function(a, b) { return (a - b); },
16794 * @property _timeoutCount
16801 * Trying to make the load order less important. Without this we get
16802 * an error if this file is loaded before the Event Utility.
16803 * @method _addListeners
16807 _addListeners: function() {
16808 var DDM = Roo.dd.DDM;
16809 if ( Roo.lib.Event && document ) {
16812 if (DDM._timeoutCount > 2000) {
16814 setTimeout(DDM._addListeners, 10);
16815 if (document && document.body) {
16816 DDM._timeoutCount += 1;
16823 * Recursively searches the immediate parent and all child nodes for
16824 * the handle element in order to determine wheter or not it was
16826 * @method handleWasClicked
16827 * @param node the html element to inspect
16830 handleWasClicked: function(node, id) {
16831 if (this.isHandle(id, node.id)) {
16834 // check to see if this is a text node child of the one we want
16835 var p = node.parentNode;
16838 if (this.isHandle(id, p.id)) {
16853 // shorter alias, save a few bytes
16854 Roo.dd.DDM = Roo.dd.DragDropMgr;
16855 Roo.dd.DDM._addListeners();
16859 * Ext JS Library 1.1.1
16860 * Copyright(c) 2006-2007, Ext JS, LLC.
16862 * Originally Released Under LGPL - original licence link has changed is not relivant.
16865 * <script type="text/javascript">
16870 * A DragDrop implementation where the linked element follows the
16871 * mouse cursor during a drag.
16872 * @extends Roo.dd.DragDrop
16874 * @param {String} id the id of the linked element
16875 * @param {String} sGroup the group of related DragDrop items
16876 * @param {object} config an object containing configurable attributes
16877 * Valid properties for DD:
16880 Roo.dd.DD = function(id, sGroup, config) {
16882 this.init(id, sGroup, config);
16886 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16889 * When set to true, the utility automatically tries to scroll the browser
16890 * window wehn a drag and drop element is dragged near the viewport boundary.
16891 * Defaults to true.
16898 * Sets the pointer offset to the distance between the linked element's top
16899 * left corner and the location the element was clicked
16900 * @method autoOffset
16901 * @param {int} iPageX the X coordinate of the click
16902 * @param {int} iPageY the Y coordinate of the click
16904 autoOffset: function(iPageX, iPageY) {
16905 var x = iPageX - this.startPageX;
16906 var y = iPageY - this.startPageY;
16907 this.setDelta(x, y);
16911 * Sets the pointer offset. You can call this directly to force the
16912 * offset to be in a particular location (e.g., pass in 0,0 to set it
16913 * to the center of the object)
16915 * @param {int} iDeltaX the distance from the left
16916 * @param {int} iDeltaY the distance from the top
16918 setDelta: function(iDeltaX, iDeltaY) {
16919 this.deltaX = iDeltaX;
16920 this.deltaY = iDeltaY;
16924 * Sets the drag element to the location of the mousedown or click event,
16925 * maintaining the cursor location relative to the location on the element
16926 * that was clicked. Override this if you want to place the element in a
16927 * location other than where the cursor is.
16928 * @method setDragElPos
16929 * @param {int} iPageX the X coordinate of the mousedown or drag event
16930 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16932 setDragElPos: function(iPageX, iPageY) {
16933 // the first time we do this, we are going to check to make sure
16934 // the element has css positioning
16936 var el = this.getDragEl();
16937 this.alignElWithMouse(el, iPageX, iPageY);
16941 * Sets the element to the location of the mousedown or click event,
16942 * maintaining the cursor location relative to the location on the element
16943 * that was clicked. Override this if you want to place the element in a
16944 * location other than where the cursor is.
16945 * @method alignElWithMouse
16946 * @param {HTMLElement} el the element to move
16947 * @param {int} iPageX the X coordinate of the mousedown or drag event
16948 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16950 alignElWithMouse: function(el, iPageX, iPageY) {
16951 var oCoord = this.getTargetCoord(iPageX, iPageY);
16952 var fly = el.dom ? el : Roo.fly(el);
16953 if (!this.deltaSetXY) {
16954 var aCoord = [oCoord.x, oCoord.y];
16956 var newLeft = fly.getLeft(true);
16957 var newTop = fly.getTop(true);
16958 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16960 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16963 this.cachePosition(oCoord.x, oCoord.y);
16964 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16969 * Saves the most recent position so that we can reset the constraints and
16970 * tick marks on-demand. We need to know this so that we can calculate the
16971 * number of pixels the element is offset from its original position.
16972 * @method cachePosition
16973 * @param iPageX the current x position (optional, this just makes it so we
16974 * don't have to look it up again)
16975 * @param iPageY the current y position (optional, this just makes it so we
16976 * don't have to look it up again)
16978 cachePosition: function(iPageX, iPageY) {
16980 this.lastPageX = iPageX;
16981 this.lastPageY = iPageY;
16983 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16984 this.lastPageX = aCoord[0];
16985 this.lastPageY = aCoord[1];
16990 * Auto-scroll the window if the dragged object has been moved beyond the
16991 * visible window boundary.
16992 * @method autoScroll
16993 * @param {int} x the drag element's x position
16994 * @param {int} y the drag element's y position
16995 * @param {int} h the height of the drag element
16996 * @param {int} w the width of the drag element
16999 autoScroll: function(x, y, h, w) {
17002 // The client height
17003 var clientH = Roo.lib.Dom.getViewWidth();
17005 // The client width
17006 var clientW = Roo.lib.Dom.getViewHeight();
17008 // The amt scrolled down
17009 var st = this.DDM.getScrollTop();
17011 // The amt scrolled right
17012 var sl = this.DDM.getScrollLeft();
17014 // Location of the bottom of the element
17017 // Location of the right of the element
17020 // The distance from the cursor to the bottom of the visible area,
17021 // adjusted so that we don't scroll if the cursor is beyond the
17022 // element drag constraints
17023 var toBot = (clientH + st - y - this.deltaY);
17025 // The distance from the cursor to the right of the visible area
17026 var toRight = (clientW + sl - x - this.deltaX);
17029 // How close to the edge the cursor must be before we scroll
17030 // var thresh = (document.all) ? 100 : 40;
17033 // How many pixels to scroll per autoscroll op. This helps to reduce
17034 // clunky scrolling. IE is more sensitive about this ... it needs this
17035 // value to be higher.
17036 var scrAmt = (document.all) ? 80 : 30;
17038 // Scroll down if we are near the bottom of the visible page and the
17039 // obj extends below the crease
17040 if ( bot > clientH && toBot < thresh ) {
17041 window.scrollTo(sl, st + scrAmt);
17044 // Scroll up if the window is scrolled down and the top of the object
17045 // goes above the top border
17046 if ( y < st && st > 0 && y - st < thresh ) {
17047 window.scrollTo(sl, st - scrAmt);
17050 // Scroll right if the obj is beyond the right border and the cursor is
17051 // near the border.
17052 if ( right > clientW && toRight < thresh ) {
17053 window.scrollTo(sl + scrAmt, st);
17056 // Scroll left if the window has been scrolled to the right and the obj
17057 // extends past the left border
17058 if ( x < sl && sl > 0 && x - sl < thresh ) {
17059 window.scrollTo(sl - scrAmt, st);
17065 * Finds the location the element should be placed if we want to move
17066 * it to where the mouse location less the click offset would place us.
17067 * @method getTargetCoord
17068 * @param {int} iPageX the X coordinate of the click
17069 * @param {int} iPageY the Y coordinate of the click
17070 * @return an object that contains the coordinates (Object.x and Object.y)
17073 getTargetCoord: function(iPageX, iPageY) {
17076 var x = iPageX - this.deltaX;
17077 var y = iPageY - this.deltaY;
17079 if (this.constrainX) {
17080 if (x < this.minX) { x = this.minX; }
17081 if (x > this.maxX) { x = this.maxX; }
17084 if (this.constrainY) {
17085 if (y < this.minY) { y = this.minY; }
17086 if (y > this.maxY) { y = this.maxY; }
17089 x = this.getTick(x, this.xTicks);
17090 y = this.getTick(y, this.yTicks);
17097 * Sets up config options specific to this class. Overrides
17098 * Roo.dd.DragDrop, but all versions of this method through the
17099 * inheritance chain are called
17101 applyConfig: function() {
17102 Roo.dd.DD.superclass.applyConfig.call(this);
17103 this.scroll = (this.config.scroll !== false);
17107 * Event that fires prior to the onMouseDown event. Overrides
17110 b4MouseDown: function(e) {
17111 // this.resetConstraints();
17112 this.autoOffset(e.getPageX(),
17117 * Event that fires prior to the onDrag event. Overrides
17120 b4Drag: function(e) {
17121 this.setDragElPos(e.getPageX(),
17125 toString: function() {
17126 return ("DD " + this.id);
17129 //////////////////////////////////////////////////////////////////////////
17130 // Debugging ygDragDrop events that can be overridden
17131 //////////////////////////////////////////////////////////////////////////
17133 startDrag: function(x, y) {
17136 onDrag: function(e) {
17139 onDragEnter: function(e, id) {
17142 onDragOver: function(e, id) {
17145 onDragOut: function(e, id) {
17148 onDragDrop: function(e, id) {
17151 endDrag: function(e) {
17158 * Ext JS Library 1.1.1
17159 * Copyright(c) 2006-2007, Ext JS, LLC.
17161 * Originally Released Under LGPL - original licence link has changed is not relivant.
17164 * <script type="text/javascript">
17168 * @class Roo.dd.DDProxy
17169 * A DragDrop implementation that inserts an empty, bordered div into
17170 * the document that follows the cursor during drag operations. At the time of
17171 * the click, the frame div is resized to the dimensions of the linked html
17172 * element, and moved to the exact location of the linked element.
17174 * References to the "frame" element refer to the single proxy element that
17175 * was created to be dragged in place of all DDProxy elements on the
17178 * @extends Roo.dd.DD
17180 * @param {String} id the id of the linked html element
17181 * @param {String} sGroup the group of related DragDrop objects
17182 * @param {object} config an object containing configurable attributes
17183 * Valid properties for DDProxy in addition to those in DragDrop:
17184 * resizeFrame, centerFrame, dragElId
17186 Roo.dd.DDProxy = function(id, sGroup, config) {
17188 this.init(id, sGroup, config);
17194 * The default drag frame div id
17195 * @property Roo.dd.DDProxy.dragElId
17199 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17201 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17204 * By default we resize the drag frame to be the same size as the element
17205 * we want to drag (this is to get the frame effect). We can turn it off
17206 * if we want a different behavior.
17207 * @property resizeFrame
17213 * By default the frame is positioned exactly where the drag element is, so
17214 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17215 * you do not have constraints on the obj is to have the drag frame centered
17216 * around the cursor. Set centerFrame to true for this effect.
17217 * @property centerFrame
17220 centerFrame: false,
17223 * Creates the proxy element if it does not yet exist
17224 * @method createFrame
17226 createFrame: function() {
17228 var body = document.body;
17230 if (!body || !body.firstChild) {
17231 setTimeout( function() { self.createFrame(); }, 50 );
17235 var div = this.getDragEl();
17238 div = document.createElement("div");
17239 div.id = this.dragElId;
17242 s.position = "absolute";
17243 s.visibility = "hidden";
17245 s.border = "2px solid #aaa";
17248 // appendChild can blow up IE if invoked prior to the window load event
17249 // while rendering a table. It is possible there are other scenarios
17250 // that would cause this to happen as well.
17251 body.insertBefore(div, body.firstChild);
17256 * Initialization for the drag frame element. Must be called in the
17257 * constructor of all subclasses
17258 * @method initFrame
17260 initFrame: function() {
17261 this.createFrame();
17264 applyConfig: function() {
17265 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17267 this.resizeFrame = (this.config.resizeFrame !== false);
17268 this.centerFrame = (this.config.centerFrame);
17269 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17273 * Resizes the drag frame to the dimensions of the clicked object, positions
17274 * it over the object, and finally displays it
17275 * @method showFrame
17276 * @param {int} iPageX X click position
17277 * @param {int} iPageY Y click position
17280 showFrame: function(iPageX, iPageY) {
17281 var el = this.getEl();
17282 var dragEl = this.getDragEl();
17283 var s = dragEl.style;
17285 this._resizeProxy();
17287 if (this.centerFrame) {
17288 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17289 Math.round(parseInt(s.height, 10)/2) );
17292 this.setDragElPos(iPageX, iPageY);
17294 Roo.fly(dragEl).show();
17298 * The proxy is automatically resized to the dimensions of the linked
17299 * element when a drag is initiated, unless resizeFrame is set to false
17300 * @method _resizeProxy
17303 _resizeProxy: function() {
17304 if (this.resizeFrame) {
17305 var el = this.getEl();
17306 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17310 // overrides Roo.dd.DragDrop
17311 b4MouseDown: function(e) {
17312 var x = e.getPageX();
17313 var y = e.getPageY();
17314 this.autoOffset(x, y);
17315 this.setDragElPos(x, y);
17318 // overrides Roo.dd.DragDrop
17319 b4StartDrag: function(x, y) {
17320 // show the drag frame
17321 this.showFrame(x, y);
17324 // overrides Roo.dd.DragDrop
17325 b4EndDrag: function(e) {
17326 Roo.fly(this.getDragEl()).hide();
17329 // overrides Roo.dd.DragDrop
17330 // By default we try to move the element to the last location of the frame.
17331 // This is so that the default behavior mirrors that of Roo.dd.DD.
17332 endDrag: function(e) {
17334 var lel = this.getEl();
17335 var del = this.getDragEl();
17337 // Show the drag frame briefly so we can get its position
17338 del.style.visibility = "";
17341 // Hide the linked element before the move to get around a Safari
17343 lel.style.visibility = "hidden";
17344 Roo.dd.DDM.moveToEl(lel, del);
17345 del.style.visibility = "hidden";
17346 lel.style.visibility = "";
17351 beforeMove : function(){
17355 afterDrag : function(){
17359 toString: function() {
17360 return ("DDProxy " + this.id);
17366 * Ext JS Library 1.1.1
17367 * Copyright(c) 2006-2007, Ext JS, LLC.
17369 * Originally Released Under LGPL - original licence link has changed is not relivant.
17372 * <script type="text/javascript">
17376 * @class Roo.dd.DDTarget
17377 * A DragDrop implementation that does not move, but can be a drop
17378 * target. You would get the same result by simply omitting implementation
17379 * for the event callbacks, but this way we reduce the processing cost of the
17380 * event listener and the callbacks.
17381 * @extends Roo.dd.DragDrop
17383 * @param {String} id the id of the element that is a drop target
17384 * @param {String} sGroup the group of related DragDrop objects
17385 * @param {object} config an object containing configurable attributes
17386 * Valid properties for DDTarget in addition to those in
17390 Roo.dd.DDTarget = function(id, sGroup, config) {
17392 this.initTarget(id, sGroup, config);
17394 if (config.listeners || config.events) {
17395 Roo.dd.DragDrop.superclass.constructor.call(this, {
17396 listeners : config.listeners || {},
17397 events : config.events || {}
17402 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17403 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17404 toString: function() {
17405 return ("DDTarget " + this.id);
17410 * Ext JS Library 1.1.1
17411 * Copyright(c) 2006-2007, Ext JS, LLC.
17413 * Originally Released Under LGPL - original licence link has changed is not relivant.
17416 * <script type="text/javascript">
17421 * @class Roo.dd.ScrollManager
17422 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17423 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17426 Roo.dd.ScrollManager = function(){
17427 var ddm = Roo.dd.DragDropMgr;
17432 var onStop = function(e){
17437 var triggerRefresh = function(){
17438 if(ddm.dragCurrent){
17439 ddm.refreshCache(ddm.dragCurrent.groups);
17443 var doScroll = function(){
17444 if(ddm.dragCurrent){
17445 var dds = Roo.dd.ScrollManager;
17447 if(proc.el.scroll(proc.dir, dds.increment)){
17451 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17456 var clearProc = function(){
17458 clearInterval(proc.id);
17465 var startProc = function(el, dir){
17469 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17472 var onFire = function(e, isDrop){
17473 if(isDrop || !ddm.dragCurrent){ return; }
17474 var dds = Roo.dd.ScrollManager;
17475 if(!dragEl || dragEl != ddm.dragCurrent){
17476 dragEl = ddm.dragCurrent;
17477 // refresh regions on drag start
17478 dds.refreshCache();
17481 var xy = Roo.lib.Event.getXY(e);
17482 var pt = new Roo.lib.Point(xy[0], xy[1]);
17483 for(var id in els){
17484 var el = els[id], r = el._region;
17485 if(r && r.contains(pt) && el.isScrollable()){
17486 if(r.bottom - pt.y <= dds.thresh){
17488 startProc(el, "down");
17491 }else if(r.right - pt.x <= dds.thresh){
17493 startProc(el, "left");
17496 }else if(pt.y - r.top <= dds.thresh){
17498 startProc(el, "up");
17501 }else if(pt.x - r.left <= dds.thresh){
17503 startProc(el, "right");
17512 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17513 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17517 * Registers new overflow element(s) to auto scroll
17518 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17520 register : function(el){
17521 if(el instanceof Array){
17522 for(var i = 0, len = el.length; i < len; i++) {
17523 this.register(el[i]);
17532 * Unregisters overflow element(s) so they are no longer scrolled
17533 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17535 unregister : function(el){
17536 if(el instanceof Array){
17537 for(var i = 0, len = el.length; i < len; i++) {
17538 this.unregister(el[i]);
17547 * The number of pixels from the edge of a container the pointer needs to be to
17548 * trigger scrolling (defaults to 25)
17554 * The number of pixels to scroll in each scroll increment (defaults to 50)
17560 * The frequency of scrolls in milliseconds (defaults to 500)
17566 * True to animate the scroll (defaults to true)
17572 * The animation duration in seconds -
17573 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17579 * Manually trigger a cache refresh.
17581 refreshCache : function(){
17582 for(var id in els){
17583 if(typeof els[id] == 'object'){ // for people extending the object prototype
17584 els[id]._region = els[id].getRegion();
17591 * Ext JS Library 1.1.1
17592 * Copyright(c) 2006-2007, Ext JS, LLC.
17594 * Originally Released Under LGPL - original licence link has changed is not relivant.
17597 * <script type="text/javascript">
17602 * @class Roo.dd.Registry
17603 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17604 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17607 Roo.dd.Registry = function(){
17610 var autoIdSeed = 0;
17612 var getId = function(el, autogen){
17613 if(typeof el == "string"){
17617 if(!id && autogen !== false){
17618 id = "roodd-" + (++autoIdSeed);
17626 * Register a drag drop element
17627 * @param {String|HTMLElement} element The id or DOM node to register
17628 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17629 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17630 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17631 * populated in the data object (if applicable):
17633 Value Description<br />
17634 --------- ------------------------------------------<br />
17635 handles Array of DOM nodes that trigger dragging<br />
17636 for the element being registered<br />
17637 isHandle True if the element passed in triggers<br />
17638 dragging itself, else false
17641 register : function(el, data){
17643 if(typeof el == "string"){
17644 el = document.getElementById(el);
17647 elements[getId(el)] = data;
17648 if(data.isHandle !== false){
17649 handles[data.ddel.id] = data;
17652 var hs = data.handles;
17653 for(var i = 0, len = hs.length; i < len; i++){
17654 handles[getId(hs[i])] = data;
17660 * Unregister a drag drop element
17661 * @param {String|HTMLElement} element The id or DOM node to unregister
17663 unregister : function(el){
17664 var id = getId(el, false);
17665 var data = elements[id];
17667 delete elements[id];
17669 var hs = data.handles;
17670 for(var i = 0, len = hs.length; i < len; i++){
17671 delete handles[getId(hs[i], false)];
17678 * Returns the handle registered for a DOM Node by id
17679 * @param {String|HTMLElement} id The DOM node or id to look up
17680 * @return {Object} handle The custom handle data
17682 getHandle : function(id){
17683 if(typeof id != "string"){ // must be element?
17686 return handles[id];
17690 * Returns the handle that is registered for the DOM node that is the target of the event
17691 * @param {Event} e The event
17692 * @return {Object} handle The custom handle data
17694 getHandleFromEvent : function(e){
17695 var t = Roo.lib.Event.getTarget(e);
17696 return t ? handles[t.id] : null;
17700 * Returns a custom data object that is registered for a DOM node by id
17701 * @param {String|HTMLElement} id The DOM node or id to look up
17702 * @return {Object} data The custom data
17704 getTarget : function(id){
17705 if(typeof id != "string"){ // must be element?
17708 return elements[id];
17712 * Returns a custom data object that is registered for the DOM node that is the target of the event
17713 * @param {Event} e The event
17714 * @return {Object} data The custom data
17716 getTargetFromEvent : function(e){
17717 var t = Roo.lib.Event.getTarget(e);
17718 return t ? elements[t.id] || handles[t.id] : null;
17723 * Ext JS Library 1.1.1
17724 * Copyright(c) 2006-2007, Ext JS, LLC.
17726 * Originally Released Under LGPL - original licence link has changed is not relivant.
17729 * <script type="text/javascript">
17734 * @class Roo.dd.StatusProxy
17735 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17736 * default drag proxy used by all Roo.dd components.
17738 * @param {Object} config
17740 Roo.dd.StatusProxy = function(config){
17741 Roo.apply(this, config);
17742 this.id = this.id || Roo.id();
17743 this.el = new Roo.Layer({
17745 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17746 {tag: "div", cls: "x-dd-drop-icon"},
17747 {tag: "div", cls: "x-dd-drag-ghost"}
17750 shadow: !config || config.shadow !== false
17752 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17753 this.dropStatus = this.dropNotAllowed;
17756 Roo.dd.StatusProxy.prototype = {
17758 * @cfg {String} dropAllowed
17759 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17761 dropAllowed : "x-dd-drop-ok",
17763 * @cfg {String} dropNotAllowed
17764 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17766 dropNotAllowed : "x-dd-drop-nodrop",
17769 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17770 * over the current target element.
17771 * @param {String} cssClass The css class for the new drop status indicator image
17773 setStatus : function(cssClass){
17774 cssClass = cssClass || this.dropNotAllowed;
17775 if(this.dropStatus != cssClass){
17776 this.el.replaceClass(this.dropStatus, cssClass);
17777 this.dropStatus = cssClass;
17782 * Resets the status indicator to the default dropNotAllowed value
17783 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17785 reset : function(clearGhost){
17786 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17787 this.dropStatus = this.dropNotAllowed;
17789 this.ghost.update("");
17794 * Updates the contents of the ghost element
17795 * @param {String} html The html that will replace the current innerHTML of the ghost element
17797 update : function(html){
17798 if(typeof html == "string"){
17799 this.ghost.update(html);
17801 this.ghost.update("");
17802 html.style.margin = "0";
17803 this.ghost.dom.appendChild(html);
17805 // ensure float = none set?? cant remember why though.
17806 var el = this.ghost.dom.firstChild;
17808 Roo.fly(el).setStyle('float', 'none');
17813 * Returns the underlying proxy {@link Roo.Layer}
17814 * @return {Roo.Layer} el
17816 getEl : function(){
17821 * Returns the ghost element
17822 * @return {Roo.Element} el
17824 getGhost : function(){
17830 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17832 hide : function(clear){
17840 * Stops the repair animation if it's currently running
17843 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17849 * Displays this proxy
17856 * Force the Layer to sync its shadow and shim positions to the element
17863 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17864 * invalid drop operation by the item being dragged.
17865 * @param {Array} xy The XY position of the element ([x, y])
17866 * @param {Function} callback The function to call after the repair is complete
17867 * @param {Object} scope The scope in which to execute the callback
17869 repair : function(xy, callback, scope){
17870 this.callback = callback;
17871 this.scope = scope;
17872 if(xy && this.animRepair !== false){
17873 this.el.addClass("x-dd-drag-repair");
17874 this.el.hideUnders(true);
17875 this.anim = this.el.shift({
17876 duration: this.repairDuration || .5,
17880 callback: this.afterRepair,
17884 this.afterRepair();
17889 afterRepair : function(){
17891 if(typeof this.callback == "function"){
17892 this.callback.call(this.scope || this);
17894 this.callback = null;
17899 * Ext JS Library 1.1.1
17900 * Copyright(c) 2006-2007, Ext JS, LLC.
17902 * Originally Released Under LGPL - original licence link has changed is not relivant.
17905 * <script type="text/javascript">
17909 * @class Roo.dd.DragSource
17910 * @extends Roo.dd.DDProxy
17911 * A simple class that provides the basic implementation needed to make any element draggable.
17913 * @param {String/HTMLElement/Element} el The container element
17914 * @param {Object} config
17916 Roo.dd.DragSource = function(el, config){
17917 this.el = Roo.get(el);
17918 this.dragData = {};
17920 Roo.apply(this, config);
17923 this.proxy = new Roo.dd.StatusProxy();
17926 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17927 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17929 this.dragging = false;
17932 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17934 * @cfg {String} dropAllowed
17935 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17937 dropAllowed : "x-dd-drop-ok",
17939 * @cfg {String} dropNotAllowed
17940 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17942 dropNotAllowed : "x-dd-drop-nodrop",
17945 * Returns the data object associated with this drag source
17946 * @return {Object} data An object containing arbitrary data
17948 getDragData : function(e){
17949 return this.dragData;
17953 onDragEnter : function(e, id){
17954 var target = Roo.dd.DragDropMgr.getDDById(id);
17955 this.cachedTarget = target;
17956 if(this.beforeDragEnter(target, e, id) !== false){
17957 if(target.isNotifyTarget){
17958 var status = target.notifyEnter(this, e, this.dragData);
17959 this.proxy.setStatus(status);
17961 this.proxy.setStatus(this.dropAllowed);
17964 if(this.afterDragEnter){
17966 * An empty function by default, but provided so that you can perform a custom action
17967 * when the dragged item enters the drop target by providing an implementation.
17968 * @param {Roo.dd.DragDrop} target The drop target
17969 * @param {Event} e The event object
17970 * @param {String} id The id of the dragged element
17971 * @method afterDragEnter
17973 this.afterDragEnter(target, e, id);
17979 * An empty function by default, but provided so that you can perform a custom action
17980 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17981 * @param {Roo.dd.DragDrop} target The drop target
17982 * @param {Event} e The event object
17983 * @param {String} id The id of the dragged element
17984 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17986 beforeDragEnter : function(target, e, id){
17991 alignElWithMouse: function() {
17992 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17997 onDragOver : function(e, id){
17998 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17999 if(this.beforeDragOver(target, e, id) !== false){
18000 if(target.isNotifyTarget){
18001 var status = target.notifyOver(this, e, this.dragData);
18002 this.proxy.setStatus(status);
18005 if(this.afterDragOver){
18007 * An empty function by default, but provided so that you can perform a custom action
18008 * while the dragged item is over the drop target by providing an implementation.
18009 * @param {Roo.dd.DragDrop} target The drop target
18010 * @param {Event} e The event object
18011 * @param {String} id The id of the dragged element
18012 * @method afterDragOver
18014 this.afterDragOver(target, e, id);
18020 * An empty function by default, but provided so that you can perform a custom action
18021 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18022 * @param {Roo.dd.DragDrop} target The drop target
18023 * @param {Event} e The event object
18024 * @param {String} id The id of the dragged element
18025 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18027 beforeDragOver : function(target, e, id){
18032 onDragOut : function(e, id){
18033 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18034 if(this.beforeDragOut(target, e, id) !== false){
18035 if(target.isNotifyTarget){
18036 target.notifyOut(this, e, this.dragData);
18038 this.proxy.reset();
18039 if(this.afterDragOut){
18041 * An empty function by default, but provided so that you can perform a custom action
18042 * after the dragged item is dragged out of the target without dropping.
18043 * @param {Roo.dd.DragDrop} target The drop target
18044 * @param {Event} e The event object
18045 * @param {String} id The id of the dragged element
18046 * @method afterDragOut
18048 this.afterDragOut(target, e, id);
18051 this.cachedTarget = null;
18055 * An empty function by default, but provided so that you can perform a custom action before the dragged
18056 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18057 * @param {Roo.dd.DragDrop} target The drop target
18058 * @param {Event} e The event object
18059 * @param {String} id The id of the dragged element
18060 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18062 beforeDragOut : function(target, e, id){
18067 onDragDrop : function(e, id){
18068 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18069 if(this.beforeDragDrop(target, e, id) !== false){
18070 if(target.isNotifyTarget){
18071 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18072 this.onValidDrop(target, e, id);
18074 this.onInvalidDrop(target, e, id);
18077 this.onValidDrop(target, e, id);
18080 if(this.afterDragDrop){
18082 * An empty function by default, but provided so that you can perform a custom action
18083 * after a valid drag drop has occurred by providing an implementation.
18084 * @param {Roo.dd.DragDrop} target The drop target
18085 * @param {Event} e The event object
18086 * @param {String} id The id of the dropped element
18087 * @method afterDragDrop
18089 this.afterDragDrop(target, e, id);
18092 delete this.cachedTarget;
18096 * An empty function by default, but provided so that you can perform a custom action before the dragged
18097 * item is dropped onto the target and optionally cancel the onDragDrop.
18098 * @param {Roo.dd.DragDrop} target The drop target
18099 * @param {Event} e The event object
18100 * @param {String} id The id of the dragged element
18101 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18103 beforeDragDrop : function(target, e, id){
18108 onValidDrop : function(target, e, id){
18110 if(this.afterValidDrop){
18112 * An empty function by default, but provided so that you can perform a custom action
18113 * after a valid drop has occurred by providing an implementation.
18114 * @param {Object} target The target DD
18115 * @param {Event} e The event object
18116 * @param {String} id The id of the dropped element
18117 * @method afterInvalidDrop
18119 this.afterValidDrop(target, e, id);
18124 getRepairXY : function(e, data){
18125 return this.el.getXY();
18129 onInvalidDrop : function(target, e, id){
18130 this.beforeInvalidDrop(target, e, id);
18131 if(this.cachedTarget){
18132 if(this.cachedTarget.isNotifyTarget){
18133 this.cachedTarget.notifyOut(this, e, this.dragData);
18135 this.cacheTarget = null;
18137 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18139 if(this.afterInvalidDrop){
18141 * An empty function by default, but provided so that you can perform a custom action
18142 * after an invalid drop has occurred by providing an implementation.
18143 * @param {Event} e The event object
18144 * @param {String} id The id of the dropped element
18145 * @method afterInvalidDrop
18147 this.afterInvalidDrop(e, id);
18152 afterRepair : function(){
18154 this.el.highlight(this.hlColor || "c3daf9");
18156 this.dragging = false;
18160 * An empty function by default, but provided so that you can perform a custom action after an invalid
18161 * drop has occurred.
18162 * @param {Roo.dd.DragDrop} target The drop target
18163 * @param {Event} e The event object
18164 * @param {String} id The id of the dragged element
18165 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18167 beforeInvalidDrop : function(target, e, id){
18172 handleMouseDown : function(e){
18173 if(this.dragging) {
18176 var data = this.getDragData(e);
18177 if(data && this.onBeforeDrag(data, e) !== false){
18178 this.dragData = data;
18180 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18185 * An empty function by default, but provided so that you can perform a custom action before the initial
18186 * drag event begins and optionally cancel it.
18187 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18188 * @param {Event} e The event object
18189 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18191 onBeforeDrag : function(data, e){
18196 * An empty function by default, but provided so that you can perform a custom action once the initial
18197 * drag event has begun. The drag cannot be canceled from this function.
18198 * @param {Number} x The x position of the click on the dragged object
18199 * @param {Number} y The y position of the click on the dragged object
18201 onStartDrag : Roo.emptyFn,
18203 // private - YUI override
18204 startDrag : function(x, y){
18205 this.proxy.reset();
18206 this.dragging = true;
18207 this.proxy.update("");
18208 this.onInitDrag(x, y);
18213 onInitDrag : function(x, y){
18214 var clone = this.el.dom.cloneNode(true);
18215 clone.id = Roo.id(); // prevent duplicate ids
18216 this.proxy.update(clone);
18217 this.onStartDrag(x, y);
18222 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18223 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18225 getProxy : function(){
18230 * Hides the drag source's {@link Roo.dd.StatusProxy}
18232 hideProxy : function(){
18234 this.proxy.reset(true);
18235 this.dragging = false;
18239 triggerCacheRefresh : function(){
18240 Roo.dd.DDM.refreshCache(this.groups);
18243 // private - override to prevent hiding
18244 b4EndDrag: function(e) {
18247 // private - override to prevent moving
18248 endDrag : function(e){
18249 this.onEndDrag(this.dragData, e);
18253 onEndDrag : function(data, e){
18256 // private - pin to cursor
18257 autoOffset : function(x, y) {
18258 this.setDelta(-12, -20);
18262 * Ext JS Library 1.1.1
18263 * Copyright(c) 2006-2007, Ext JS, LLC.
18265 * Originally Released Under LGPL - original licence link has changed is not relivant.
18268 * <script type="text/javascript">
18273 * @class Roo.dd.DropTarget
18274 * @extends Roo.dd.DDTarget
18275 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18276 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18278 * @param {String/HTMLElement/Element} el The container element
18279 * @param {Object} config
18281 Roo.dd.DropTarget = function(el, config){
18282 this.el = Roo.get(el);
18284 var listeners = false; ;
18285 if (config && config.listeners) {
18286 listeners= config.listeners;
18287 delete config.listeners;
18289 Roo.apply(this, config);
18291 if(this.containerScroll){
18292 Roo.dd.ScrollManager.register(this.el);
18296 * @scope Roo.dd.DropTarget
18301 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18302 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18303 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18305 * IMPORTANT : it should set this.overClass and this.dropAllowed
18307 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18308 * @param {Event} e The event
18309 * @param {Object} data An object containing arbitrary data supplied by the drag source
18315 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18316 * This method will be called on every mouse movement while the drag source is over the drop target.
18317 * This default implementation simply returns the dropAllowed config value.
18319 * IMPORTANT : it should set this.dropAllowed
18321 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18322 * @param {Event} e The event
18323 * @param {Object} data An object containing arbitrary data supplied by the drag source
18329 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18330 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18331 * overClass (if any) from the drop element.
18332 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18333 * @param {Event} e The event
18334 * @param {Object} data An object containing arbitrary data supplied by the drag source
18340 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18341 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18342 * implementation that does something to process the drop event and returns true so that the drag source's
18343 * repair action does not run.
18345 * IMPORTANT : it should set this.success
18347 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18348 * @param {Event} e The event
18349 * @param {Object} data An object containing arbitrary data supplied by the drag source
18355 Roo.dd.DropTarget.superclass.constructor.call( this,
18357 this.ddGroup || this.group,
18360 listeners : listeners || {}
18368 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18370 * @cfg {String} overClass
18371 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18374 * @cfg {String} ddGroup
18375 * The drag drop group to handle drop events for
18379 * @cfg {String} dropAllowed
18380 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18382 dropAllowed : "x-dd-drop-ok",
18384 * @cfg {String} dropNotAllowed
18385 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18387 dropNotAllowed : "x-dd-drop-nodrop",
18389 * @cfg {boolean} success
18390 * set this after drop listener..
18394 * @cfg {boolean|String} valid true/false or string (add/sub/ok/nodrop)
18395 * if the drop point is valid for over/enter..
18402 isNotifyTarget : true,
18407 notifyEnter : function(dd, e, data){
18409 this.fireEvent('enter', dd, e, data);
18410 if(this.overClass){
18411 this.el.addClass(this.overClass);
18413 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18414 this.valid ? this.dropAllowed : this.dropNotAllowed
18421 notifyOver : function(dd, e, data){
18423 this.fireEvent('over', dd, e, data);
18424 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18425 this.valid ? this.dropAllowed : this.dropNotAllowed
18432 notifyOut : function(dd, e, data){
18433 this.fireEvent('out', dd, e, data);
18434 if(this.overClass){
18435 this.el.removeClass(this.overClass);
18442 notifyDrop : function(dd, e, data){
18443 this.success = false;
18444 this.fireEvent('drop', dd, e, data);
18445 return this.success;
18449 * Ext JS Library 1.1.1
18450 * Copyright(c) 2006-2007, Ext JS, LLC.
18452 * Originally Released Under LGPL - original licence link has changed is not relivant.
18455 * <script type="text/javascript">
18460 * @class Roo.dd.DragZone
18461 * @extends Roo.dd.DragSource
18462 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18463 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18465 * @param {String/HTMLElement/Element} el The container element
18466 * @param {Object} config
18468 Roo.dd.DragZone = function(el, config){
18469 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18470 if(this.containerScroll){
18471 Roo.dd.ScrollManager.register(this.el);
18475 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18477 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18478 * for auto scrolling during drag operations.
18481 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18482 * method after a failed drop (defaults to "c3daf9" - light blue)
18486 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18487 * for a valid target to drag based on the mouse down. Override this method
18488 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18489 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18490 * @param {EventObject} e The mouse down event
18491 * @return {Object} The dragData
18493 getDragData : function(e){
18494 return Roo.dd.Registry.getHandleFromEvent(e);
18498 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18499 * this.dragData.ddel
18500 * @param {Number} x The x position of the click on the dragged object
18501 * @param {Number} y The y position of the click on the dragged object
18502 * @return {Boolean} true to continue the drag, false to cancel
18504 onInitDrag : function(x, y){
18505 this.proxy.update(this.dragData.ddel.cloneNode(true));
18506 this.onStartDrag(x, y);
18511 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18513 afterRepair : function(){
18515 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18517 this.dragging = false;
18521 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18522 * the XY of this.dragData.ddel
18523 * @param {EventObject} e The mouse up event
18524 * @return {Array} The xy location (e.g. [100, 200])
18526 getRepairXY : function(e){
18527 return Roo.Element.fly(this.dragData.ddel).getXY();
18531 * Ext JS Library 1.1.1
18532 * Copyright(c) 2006-2007, Ext JS, LLC.
18534 * Originally Released Under LGPL - original licence link has changed is not relivant.
18537 * <script type="text/javascript">
18540 * @class Roo.dd.DropZone
18541 * @extends Roo.dd.DropTarget
18542 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18543 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18545 * @param {String/HTMLElement/Element} el The container element
18546 * @param {Object} config
18548 Roo.dd.DropZone = function(el, config){
18549 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18552 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18554 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18555 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18556 * provide your own custom lookup.
18557 * @param {Event} e The event
18558 * @return {Object} data The custom data
18560 getTargetFromEvent : function(e){
18561 return Roo.dd.Registry.getTargetFromEvent(e);
18565 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18566 * that it has registered. This method has no default implementation and should be overridden to provide
18567 * node-specific processing if necessary.
18568 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18569 * {@link #getTargetFromEvent} for this node)
18570 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18571 * @param {Event} e The event
18572 * @param {Object} data An object containing arbitrary data supplied by the drag source
18574 onNodeEnter : function(n, dd, e, data){
18579 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18580 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18581 * overridden to provide the proper feedback.
18582 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18583 * {@link #getTargetFromEvent} for this node)
18584 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18585 * @param {Event} e The event
18586 * @param {Object} data An object containing arbitrary data supplied by the drag source
18587 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18588 * underlying {@link Roo.dd.StatusProxy} can be updated
18590 onNodeOver : function(n, dd, e, data){
18591 return this.dropAllowed;
18595 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18596 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18597 * node-specific processing if necessary.
18598 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18599 * {@link #getTargetFromEvent} for this node)
18600 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18601 * @param {Event} e The event
18602 * @param {Object} data An object containing arbitrary data supplied by the drag source
18604 onNodeOut : function(n, dd, e, data){
18609 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18610 * the drop node. The default implementation returns false, so it should be overridden to provide the
18611 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18612 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18613 * {@link #getTargetFromEvent} for this node)
18614 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18615 * @param {Event} e The event
18616 * @param {Object} data An object containing arbitrary data supplied by the drag source
18617 * @return {Boolean} True if the drop was valid, else false
18619 onNodeDrop : function(n, dd, e, data){
18624 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18625 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18626 * it should be overridden to provide the proper feedback if necessary.
18627 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18628 * @param {Event} e The event
18629 * @param {Object} data An object containing arbitrary data supplied by the drag source
18630 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18631 * underlying {@link Roo.dd.StatusProxy} can be updated
18633 onContainerOver : function(dd, e, data){
18634 return this.dropNotAllowed;
18638 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18639 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18640 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18641 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18642 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18643 * @param {Event} e The event
18644 * @param {Object} data An object containing arbitrary data supplied by the drag source
18645 * @return {Boolean} True if the drop was valid, else false
18647 onContainerDrop : function(dd, e, data){
18652 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18653 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18654 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18655 * you should override this method and provide a custom implementation.
18656 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18657 * @param {Event} e The event
18658 * @param {Object} data An object containing arbitrary data supplied by the drag source
18659 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18660 * underlying {@link Roo.dd.StatusProxy} can be updated
18662 notifyEnter : function(dd, e, data){
18663 return this.dropNotAllowed;
18667 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18668 * This method will be called on every mouse movement while the drag source is over the drop zone.
18669 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18670 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18671 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18672 * registered node, it will call {@link #onContainerOver}.
18673 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18674 * @param {Event} e The event
18675 * @param {Object} data An object containing arbitrary data supplied by the drag source
18676 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18677 * underlying {@link Roo.dd.StatusProxy} can be updated
18679 notifyOver : function(dd, e, data){
18680 var n = this.getTargetFromEvent(e);
18681 if(!n){ // not over valid drop target
18682 if(this.lastOverNode){
18683 this.onNodeOut(this.lastOverNode, dd, e, data);
18684 this.lastOverNode = null;
18686 return this.onContainerOver(dd, e, data);
18688 if(this.lastOverNode != n){
18689 if(this.lastOverNode){
18690 this.onNodeOut(this.lastOverNode, dd, e, data);
18692 this.onNodeEnter(n, dd, e, data);
18693 this.lastOverNode = n;
18695 return this.onNodeOver(n, dd, e, data);
18699 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18700 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18701 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18702 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18703 * @param {Event} e The event
18704 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18706 notifyOut : function(dd, e, data){
18707 if(this.lastOverNode){
18708 this.onNodeOut(this.lastOverNode, dd, e, data);
18709 this.lastOverNode = null;
18714 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18715 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18716 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18717 * otherwise it will call {@link #onContainerDrop}.
18718 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18719 * @param {Event} e The event
18720 * @param {Object} data An object containing arbitrary data supplied by the drag source
18721 * @return {Boolean} True if the drop was valid, else false
18723 notifyDrop : function(dd, e, data){
18724 if(this.lastOverNode){
18725 this.onNodeOut(this.lastOverNode, dd, e, data);
18726 this.lastOverNode = null;
18728 var n = this.getTargetFromEvent(e);
18730 this.onNodeDrop(n, dd, e, data) :
18731 this.onContainerDrop(dd, e, data);
18735 triggerCacheRefresh : function(){
18736 Roo.dd.DDM.refreshCache(this.groups);
18740 * Ext JS Library 1.1.1
18741 * Copyright(c) 2006-2007, Ext JS, LLC.
18743 * Originally Released Under LGPL - original licence link has changed is not relivant.
18746 * <script type="text/javascript">
18751 * @class Roo.data.SortTypes
18753 * Defines the default sorting (casting?) comparison functions used when sorting data.
18755 Roo.data.SortTypes = {
18757 * Default sort that does nothing
18758 * @param {Mixed} s The value being converted
18759 * @return {Mixed} The comparison value
18761 none : function(s){
18766 * The regular expression used to strip tags
18770 stripTagsRE : /<\/?[^>]+>/gi,
18773 * Strips all HTML tags to sort on text only
18774 * @param {Mixed} s The value being converted
18775 * @return {String} The comparison value
18777 asText : function(s){
18778 return String(s).replace(this.stripTagsRE, "");
18782 * Strips all HTML tags to sort on text only - Case insensitive
18783 * @param {Mixed} s The value being converted
18784 * @return {String} The comparison value
18786 asUCText : function(s){
18787 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18791 * Case insensitive string
18792 * @param {Mixed} s The value being converted
18793 * @return {String} The comparison value
18795 asUCString : function(s) {
18796 return String(s).toUpperCase();
18801 * @param {Mixed} s The value being converted
18802 * @return {Number} The comparison value
18804 asDate : function(s) {
18808 if(s instanceof Date){
18809 return s.getTime();
18811 return Date.parse(String(s));
18816 * @param {Mixed} s The value being converted
18817 * @return {Float} The comparison value
18819 asFloat : function(s) {
18820 var val = parseFloat(String(s).replace(/,/g, ""));
18821 if(isNaN(val)) val = 0;
18827 * @param {Mixed} s The value being converted
18828 * @return {Number} The comparison value
18830 asInt : function(s) {
18831 var val = parseInt(String(s).replace(/,/g, ""));
18832 if(isNaN(val)) val = 0;
18837 * Ext JS Library 1.1.1
18838 * Copyright(c) 2006-2007, Ext JS, LLC.
18840 * Originally Released Under LGPL - original licence link has changed is not relivant.
18843 * <script type="text/javascript">
18847 * @class Roo.data.Record
18848 * Instances of this class encapsulate both record <em>definition</em> information, and record
18849 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18850 * to access Records cached in an {@link Roo.data.Store} object.<br>
18852 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18853 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18856 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18858 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18859 * {@link #create}. The parameters are the same.
18860 * @param {Array} data An associative Array of data values keyed by the field name.
18861 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18862 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18863 * not specified an integer id is generated.
18865 Roo.data.Record = function(data, id){
18866 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18871 * Generate a constructor for a specific record layout.
18872 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18873 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18874 * Each field definition object may contain the following properties: <ul>
18875 * <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,
18876 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18877 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18878 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18879 * is being used, then this is a string containing the javascript expression to reference the data relative to
18880 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18881 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18882 * this may be omitted.</p></li>
18883 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18884 * <ul><li>auto (Default, implies no conversion)</li>
18889 * <li>date</li></ul></p></li>
18890 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18891 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18892 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18893 * by the Reader into an object that will be stored in the Record. It is passed the
18894 * following parameters:<ul>
18895 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18897 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18899 * <br>usage:<br><pre><code>
18900 var TopicRecord = Roo.data.Record.create(
18901 {name: 'title', mapping: 'topic_title'},
18902 {name: 'author', mapping: 'username'},
18903 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18904 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18905 {name: 'lastPoster', mapping: 'user2'},
18906 {name: 'excerpt', mapping: 'post_text'}
18909 var myNewRecord = new TopicRecord({
18910 title: 'Do my job please',
18913 lastPost: new Date(),
18914 lastPoster: 'Animal',
18915 excerpt: 'No way dude!'
18917 myStore.add(myNewRecord);
18922 Roo.data.Record.create = function(o){
18923 var f = function(){
18924 f.superclass.constructor.apply(this, arguments);
18926 Roo.extend(f, Roo.data.Record);
18927 var p = f.prototype;
18928 p.fields = new Roo.util.MixedCollection(false, function(field){
18931 for(var i = 0, len = o.length; i < len; i++){
18932 p.fields.add(new Roo.data.Field(o[i]));
18934 f.getField = function(name){
18935 return p.fields.get(name);
18940 Roo.data.Record.AUTO_ID = 1000;
18941 Roo.data.Record.EDIT = 'edit';
18942 Roo.data.Record.REJECT = 'reject';
18943 Roo.data.Record.COMMIT = 'commit';
18945 Roo.data.Record.prototype = {
18947 * Readonly flag - true if this record has been modified.
18956 join : function(store){
18957 this.store = store;
18961 * Set the named field to the specified value.
18962 * @param {String} name The name of the field to set.
18963 * @param {Object} value The value to set the field to.
18965 set : function(name, value){
18966 if(this.data[name] == value){
18970 if(!this.modified){
18971 this.modified = {};
18973 if(typeof this.modified[name] == 'undefined'){
18974 this.modified[name] = this.data[name];
18976 this.data[name] = value;
18978 this.store.afterEdit(this);
18983 * Get the value of the named field.
18984 * @param {String} name The name of the field to get the value of.
18985 * @return {Object} The value of the field.
18987 get : function(name){
18988 return this.data[name];
18992 beginEdit : function(){
18993 this.editing = true;
18994 this.modified = {};
18998 cancelEdit : function(){
18999 this.editing = false;
19000 delete this.modified;
19004 endEdit : function(){
19005 this.editing = false;
19006 if(this.dirty && this.store){
19007 this.store.afterEdit(this);
19012 * Usually called by the {@link Roo.data.Store} which owns the Record.
19013 * Rejects all changes made to the Record since either creation, or the last commit operation.
19014 * Modified fields are reverted to their original values.
19016 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19017 * of reject operations.
19019 reject : function(){
19020 var m = this.modified;
19022 if(typeof m[n] != "function"){
19023 this.data[n] = m[n];
19026 this.dirty = false;
19027 delete this.modified;
19028 this.editing = false;
19030 this.store.afterReject(this);
19035 * Usually called by the {@link Roo.data.Store} which owns the Record.
19036 * Commits all changes made to the Record since either creation, or the last commit operation.
19038 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19039 * of commit operations.
19041 commit : function(){
19042 this.dirty = false;
19043 delete this.modified;
19044 this.editing = false;
19046 this.store.afterCommit(this);
19051 hasError : function(){
19052 return this.error != null;
19056 clearError : function(){
19061 * Creates a copy of this record.
19062 * @param {String} id (optional) A new record id if you don't want to use this record's id
19065 copy : function(newId) {
19066 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19070 * Ext JS Library 1.1.1
19071 * Copyright(c) 2006-2007, Ext JS, LLC.
19073 * Originally Released Under LGPL - original licence link has changed is not relivant.
19076 * <script type="text/javascript">
19082 * @class Roo.data.Store
19083 * @extends Roo.util.Observable
19084 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19085 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19087 * 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
19088 * has no knowledge of the format of the data returned by the Proxy.<br>
19090 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19091 * instances from the data object. These records are cached and made available through accessor functions.
19093 * Creates a new Store.
19094 * @param {Object} config A config object containing the objects needed for the Store to access data,
19095 * and read the data into Records.
19097 Roo.data.Store = function(config){
19098 this.data = new Roo.util.MixedCollection(false);
19099 this.data.getKey = function(o){
19102 this.baseParams = {};
19104 this.paramNames = {
19111 if(config && config.data){
19112 this.inlineData = config.data;
19113 delete config.data;
19116 Roo.apply(this, config);
19118 if(this.reader){ // reader passed
19119 this.reader = Roo.factory(this.reader, Roo.data);
19120 this.reader.xmodule = this.xmodule || false;
19121 if(!this.recordType){
19122 this.recordType = this.reader.recordType;
19124 if(this.reader.onMetaChange){
19125 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19129 if(this.recordType){
19130 this.fields = this.recordType.prototype.fields;
19132 this.modified = [];
19136 * @event datachanged
19137 * Fires when the data cache has changed, and a widget which is using this Store
19138 * as a Record cache should refresh its view.
19139 * @param {Store} this
19141 datachanged : true,
19143 * @event metachange
19144 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19145 * @param {Store} this
19146 * @param {Object} meta The JSON metadata
19151 * Fires when Records have been added to the Store
19152 * @param {Store} this
19153 * @param {Roo.data.Record[]} records The array of Records added
19154 * @param {Number} index The index at which the record(s) were added
19159 * Fires when a Record has been removed from the Store
19160 * @param {Store} this
19161 * @param {Roo.data.Record} record The Record that was removed
19162 * @param {Number} index The index at which the record was removed
19167 * Fires when a Record has been updated
19168 * @param {Store} this
19169 * @param {Roo.data.Record} record The Record that was updated
19170 * @param {String} operation The update operation being performed. Value may be one of:
19172 Roo.data.Record.EDIT
19173 Roo.data.Record.REJECT
19174 Roo.data.Record.COMMIT
19180 * Fires when the data cache has been cleared.
19181 * @param {Store} this
19185 * @event beforeload
19186 * Fires before a request is made for a new data object. If the beforeload handler returns false
19187 * the load action will be canceled.
19188 * @param {Store} this
19189 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19194 * Fires after a new set of Records has been loaded.
19195 * @param {Store} this
19196 * @param {Roo.data.Record[]} records The Records that were loaded
19197 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19201 * @event loadexception
19202 * Fires if an exception occurs in the Proxy during loading.
19203 * Called with the signature of the Proxy's "loadexception" event.
19204 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19207 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19208 * @param {Object} load options
19209 * @param {Object} jsonData from your request (normally this contains the Exception)
19211 loadexception : true
19215 this.proxy = Roo.factory(this.proxy, Roo.data);
19216 this.proxy.xmodule = this.xmodule || false;
19217 this.relayEvents(this.proxy, ["loadexception"]);
19219 this.sortToggle = {};
19221 Roo.data.Store.superclass.constructor.call(this);
19223 if(this.inlineData){
19224 this.loadData(this.inlineData);
19225 delete this.inlineData;
19228 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19230 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19231 * without a remote query - used by combo/forms at present.
19235 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19238 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19241 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19242 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19245 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19246 * on any HTTP request
19249 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19252 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19253 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19255 remoteSort : false,
19258 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19259 * loaded or when a record is removed. (defaults to false).
19261 pruneModifiedRecords : false,
19264 lastOptions : null,
19267 * Add Records to the Store and fires the add event.
19268 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19270 add : function(records){
19271 records = [].concat(records);
19272 for(var i = 0, len = records.length; i < len; i++){
19273 records[i].join(this);
19275 var index = this.data.length;
19276 this.data.addAll(records);
19277 this.fireEvent("add", this, records, index);
19281 * Remove a Record from the Store and fires the remove event.
19282 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19284 remove : function(record){
19285 var index = this.data.indexOf(record);
19286 this.data.removeAt(index);
19287 if(this.pruneModifiedRecords){
19288 this.modified.remove(record);
19290 this.fireEvent("remove", this, record, index);
19294 * Remove all Records from the Store and fires the clear event.
19296 removeAll : function(){
19298 if(this.pruneModifiedRecords){
19299 this.modified = [];
19301 this.fireEvent("clear", this);
19305 * Inserts Records to the Store at the given index and fires the add event.
19306 * @param {Number} index The start index at which to insert the passed Records.
19307 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19309 insert : function(index, records){
19310 records = [].concat(records);
19311 for(var i = 0, len = records.length; i < len; i++){
19312 this.data.insert(index, records[i]);
19313 records[i].join(this);
19315 this.fireEvent("add", this, records, index);
19319 * Get the index within the cache of the passed Record.
19320 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19321 * @return {Number} The index of the passed Record. Returns -1 if not found.
19323 indexOf : function(record){
19324 return this.data.indexOf(record);
19328 * Get the index within the cache of the Record with the passed id.
19329 * @param {String} id The id of the Record to find.
19330 * @return {Number} The index of the Record. Returns -1 if not found.
19332 indexOfId : function(id){
19333 return this.data.indexOfKey(id);
19337 * Get the Record with the specified id.
19338 * @param {String} id The id of the Record to find.
19339 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19341 getById : function(id){
19342 return this.data.key(id);
19346 * Get the Record at the specified index.
19347 * @param {Number} index The index of the Record to find.
19348 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19350 getAt : function(index){
19351 return this.data.itemAt(index);
19355 * Returns a range of Records between specified indices.
19356 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19357 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19358 * @return {Roo.data.Record[]} An array of Records
19360 getRange : function(start, end){
19361 return this.data.getRange(start, end);
19365 storeOptions : function(o){
19366 o = Roo.apply({}, o);
19369 this.lastOptions = o;
19373 * Loads the Record cache from the configured Proxy using the configured Reader.
19375 * If using remote paging, then the first load call must specify the <em>start</em>
19376 * and <em>limit</em> properties in the options.params property to establish the initial
19377 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19379 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19380 * and this call will return before the new data has been loaded. Perform any post-processing
19381 * in a callback function, or in a "load" event handler.</strong>
19383 * @param {Object} options An object containing properties which control loading options:<ul>
19384 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19385 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19386 * passed the following arguments:<ul>
19387 * <li>r : Roo.data.Record[]</li>
19388 * <li>options: Options object from the load call</li>
19389 * <li>success: Boolean success indicator</li></ul></li>
19390 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19391 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19394 load : function(options){
19395 options = options || {};
19396 if(this.fireEvent("beforeload", this, options) !== false){
19397 this.storeOptions(options);
19398 var p = Roo.apply(options.params || {}, this.baseParams);
19399 // if meta was not loaded from remote source.. try requesting it.
19400 if (!this.reader.metaFromRemote) {
19401 p._requestMeta = 1;
19403 if(this.sortInfo && this.remoteSort){
19404 var pn = this.paramNames;
19405 p[pn["sort"]] = this.sortInfo.field;
19406 p[pn["dir"]] = this.sortInfo.direction;
19408 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19413 * Reloads the Record cache from the configured Proxy using the configured Reader and
19414 * the options from the last load operation performed.
19415 * @param {Object} options (optional) An object containing properties which may override the options
19416 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19417 * the most recently used options are reused).
19419 reload : function(options){
19420 this.load(Roo.applyIf(options||{}, this.lastOptions));
19424 // Called as a callback by the Reader during a load operation.
19425 loadRecords : function(o, options, success){
19426 if(!o || success === false){
19427 if(success !== false){
19428 this.fireEvent("load", this, [], options);
19430 if(options.callback){
19431 options.callback.call(options.scope || this, [], options, false);
19435 // if data returned failure - throw an exception.
19436 if (o.success === false) {
19437 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19440 var r = o.records, t = o.totalRecords || r.length;
19441 if(!options || options.add !== true){
19442 if(this.pruneModifiedRecords){
19443 this.modified = [];
19445 for(var i = 0, len = r.length; i < len; i++){
19449 this.data = this.snapshot;
19450 delete this.snapshot;
19453 this.data.addAll(r);
19454 this.totalLength = t;
19456 this.fireEvent("datachanged", this);
19458 this.totalLength = Math.max(t, this.data.length+r.length);
19461 this.fireEvent("load", this, r, options);
19462 if(options.callback){
19463 options.callback.call(options.scope || this, r, options, true);
19468 * Loads data from a passed data block. A Reader which understands the format of the data
19469 * must have been configured in the constructor.
19470 * @param {Object} data The data block from which to read the Records. The format of the data expected
19471 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19472 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19474 loadData : function(o, append){
19475 var r = this.reader.readRecords(o);
19476 this.loadRecords(r, {add: append}, true);
19480 * Gets the number of cached records.
19482 * <em>If using paging, this may not be the total size of the dataset. If the data object
19483 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19484 * the data set size</em>
19486 getCount : function(){
19487 return this.data.length || 0;
19491 * Gets the total number of records in the dataset as returned by the server.
19493 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19494 * the dataset size</em>
19496 getTotalCount : function(){
19497 return this.totalLength || 0;
19501 * Returns the sort state of the Store as an object with two properties:
19503 field {String} The name of the field by which the Records are sorted
19504 direction {String} The sort order, "ASC" or "DESC"
19507 getSortState : function(){
19508 return this.sortInfo;
19512 applySort : function(){
19513 if(this.sortInfo && !this.remoteSort){
19514 var s = this.sortInfo, f = s.field;
19515 var st = this.fields.get(f).sortType;
19516 var fn = function(r1, r2){
19517 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19518 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19520 this.data.sort(s.direction, fn);
19521 if(this.snapshot && this.snapshot != this.data){
19522 this.snapshot.sort(s.direction, fn);
19528 * Sets the default sort column and order to be used by the next load operation.
19529 * @param {String} fieldName The name of the field to sort by.
19530 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19532 setDefaultSort : function(field, dir){
19533 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19537 * Sort the Records.
19538 * If remote sorting is used, the sort is performed on the server, and the cache is
19539 * reloaded. If local sorting is used, the cache is sorted internally.
19540 * @param {String} fieldName The name of the field to sort by.
19541 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19543 sort : function(fieldName, dir){
19544 var f = this.fields.get(fieldName);
19546 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19547 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19552 this.sortToggle[f.name] = dir;
19553 this.sortInfo = {field: f.name, direction: dir};
19554 if(!this.remoteSort){
19556 this.fireEvent("datachanged", this);
19558 this.load(this.lastOptions);
19563 * Calls the specified function for each of the Records in the cache.
19564 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19565 * Returning <em>false</em> aborts and exits the iteration.
19566 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19568 each : function(fn, scope){
19569 this.data.each(fn, scope);
19573 * Gets all records modified since the last commit. Modified records are persisted across load operations
19574 * (e.g., during paging).
19575 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19577 getModifiedRecords : function(){
19578 return this.modified;
19582 createFilterFn : function(property, value, anyMatch){
19583 if(!value.exec){ // not a regex
19584 value = String(value);
19585 if(value.length == 0){
19588 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19590 return function(r){
19591 return value.test(r.data[property]);
19596 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19597 * @param {String} property A field on your records
19598 * @param {Number} start The record index to start at (defaults to 0)
19599 * @param {Number} end The last record index to include (defaults to length - 1)
19600 * @return {Number} The sum
19602 sum : function(property, start, end){
19603 var rs = this.data.items, v = 0;
19604 start = start || 0;
19605 end = (end || end === 0) ? end : rs.length-1;
19607 for(var i = start; i <= end; i++){
19608 v += (rs[i].data[property] || 0);
19614 * Filter the records by a specified property.
19615 * @param {String} field A field on your records
19616 * @param {String/RegExp} value Either a string that the field
19617 * should start with or a RegExp to test against the field
19618 * @param {Boolean} anyMatch True to match any part not just the beginning
19620 filter : function(property, value, anyMatch){
19621 var fn = this.createFilterFn(property, value, anyMatch);
19622 return fn ? this.filterBy(fn) : this.clearFilter();
19626 * Filter by a function. The specified function will be called with each
19627 * record in this data source. If the function returns true the record is included,
19628 * otherwise it is filtered.
19629 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19630 * @param {Object} scope (optional) The scope of the function (defaults to this)
19632 filterBy : function(fn, scope){
19633 this.snapshot = this.snapshot || this.data;
19634 this.data = this.queryBy(fn, scope||this);
19635 this.fireEvent("datachanged", this);
19639 * Query the records by a specified property.
19640 * @param {String} field A field on your records
19641 * @param {String/RegExp} value Either a string that the field
19642 * should start with or a RegExp to test against the field
19643 * @param {Boolean} anyMatch True to match any part not just the beginning
19644 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19646 query : function(property, value, anyMatch){
19647 var fn = this.createFilterFn(property, value, anyMatch);
19648 return fn ? this.queryBy(fn) : this.data.clone();
19652 * Query by a function. The specified function will be called with each
19653 * record in this data source. If the function returns true the record is included
19655 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19656 * @param {Object} scope (optional) The scope of the function (defaults to this)
19657 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19659 queryBy : function(fn, scope){
19660 var data = this.snapshot || this.data;
19661 return data.filterBy(fn, scope||this);
19665 * Collects unique values for a particular dataIndex from this store.
19666 * @param {String} dataIndex The property to collect
19667 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19668 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19669 * @return {Array} An array of the unique values
19671 collect : function(dataIndex, allowNull, bypassFilter){
19672 var d = (bypassFilter === true && this.snapshot) ?
19673 this.snapshot.items : this.data.items;
19674 var v, sv, r = [], l = {};
19675 for(var i = 0, len = d.length; i < len; i++){
19676 v = d[i].data[dataIndex];
19678 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19687 * Revert to a view of the Record cache with no filtering applied.
19688 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19690 clearFilter : function(suppressEvent){
19691 if(this.snapshot && this.snapshot != this.data){
19692 this.data = this.snapshot;
19693 delete this.snapshot;
19694 if(suppressEvent !== true){
19695 this.fireEvent("datachanged", this);
19701 afterEdit : function(record){
19702 if(this.modified.indexOf(record) == -1){
19703 this.modified.push(record);
19705 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19709 afterReject : function(record){
19710 this.modified.remove(record);
19711 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19715 afterCommit : function(record){
19716 this.modified.remove(record);
19717 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19721 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19722 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19724 commitChanges : function(){
19725 var m = this.modified.slice(0);
19726 this.modified = [];
19727 for(var i = 0, len = m.length; i < len; i++){
19733 * Cancel outstanding changes on all changed records.
19735 rejectChanges : function(){
19736 var m = this.modified.slice(0);
19737 this.modified = [];
19738 for(var i = 0, len = m.length; i < len; i++){
19743 onMetaChange : function(meta, rtype, o){
19744 this.recordType = rtype;
19745 this.fields = rtype.prototype.fields;
19746 delete this.snapshot;
19747 this.sortInfo = meta.sortInfo || this.sortInfo;
19748 this.modified = [];
19749 this.fireEvent('metachange', this, this.reader.meta);
19753 * Ext JS Library 1.1.1
19754 * Copyright(c) 2006-2007, Ext JS, LLC.
19756 * Originally Released Under LGPL - original licence link has changed is not relivant.
19759 * <script type="text/javascript">
19763 * @class Roo.data.SimpleStore
19764 * @extends Roo.data.Store
19765 * Small helper class to make creating Stores from Array data easier.
19766 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19767 * @cfg {Array} fields An array of field definition objects, or field name strings.
19768 * @cfg {Array} data The multi-dimensional array of data
19770 * @param {Object} config
19772 Roo.data.SimpleStore = function(config){
19773 Roo.data.SimpleStore.superclass.constructor.call(this, {
19775 reader: new Roo.data.ArrayReader({
19778 Roo.data.Record.create(config.fields)
19780 proxy : new Roo.data.MemoryProxy(config.data)
19784 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19786 * Ext JS Library 1.1.1
19787 * Copyright(c) 2006-2007, Ext JS, LLC.
19789 * Originally Released Under LGPL - original licence link has changed is not relivant.
19792 * <script type="text/javascript">
19797 * @extends Roo.data.Store
19798 * @class Roo.data.JsonStore
19799 * Small helper class to make creating Stores for JSON data easier. <br/>
19801 var store = new Roo.data.JsonStore({
19802 url: 'get-images.php',
19804 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19807 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19808 * JsonReader and HttpProxy (unless inline data is provided).</b>
19809 * @cfg {Array} fields An array of field definition objects, or field name strings.
19811 * @param {Object} config
19813 Roo.data.JsonStore = function(c){
19814 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19815 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19816 reader: new Roo.data.JsonReader(c, c.fields)
19819 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19821 * Ext JS Library 1.1.1
19822 * Copyright(c) 2006-2007, Ext JS, LLC.
19824 * Originally Released Under LGPL - original licence link has changed is not relivant.
19827 * <script type="text/javascript">
19831 Roo.data.Field = function(config){
19832 if(typeof config == "string"){
19833 config = {name: config};
19835 Roo.apply(this, config);
19838 this.type = "auto";
19841 var st = Roo.data.SortTypes;
19842 // named sortTypes are supported, here we look them up
19843 if(typeof this.sortType == "string"){
19844 this.sortType = st[this.sortType];
19847 // set default sortType for strings and dates
19848 if(!this.sortType){
19851 this.sortType = st.asUCString;
19854 this.sortType = st.asDate;
19857 this.sortType = st.none;
19862 var stripRe = /[\$,%]/g;
19864 // prebuilt conversion function for this field, instead of
19865 // switching every time we're reading a value
19867 var cv, dateFormat = this.dateFormat;
19872 cv = function(v){ return v; };
19875 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19879 return v !== undefined && v !== null && v !== '' ?
19880 parseInt(String(v).replace(stripRe, ""), 10) : '';
19885 return v !== undefined && v !== null && v !== '' ?
19886 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19891 cv = function(v){ return v === true || v === "true" || v == 1; };
19898 if(v instanceof Date){
19902 if(dateFormat == "timestamp"){
19903 return new Date(v*1000);
19905 return Date.parseDate(v, dateFormat);
19907 var parsed = Date.parse(v);
19908 return parsed ? new Date(parsed) : null;
19917 Roo.data.Field.prototype = {
19925 * Ext JS Library 1.1.1
19926 * Copyright(c) 2006-2007, Ext JS, LLC.
19928 * Originally Released Under LGPL - original licence link has changed is not relivant.
19931 * <script type="text/javascript">
19934 // Base class for reading structured data from a data source. This class is intended to be
19935 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19938 * @class Roo.data.DataReader
19939 * Base class for reading structured data from a data source. This class is intended to be
19940 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19943 Roo.data.DataReader = function(meta, recordType){
19947 this.recordType = recordType instanceof Array ?
19948 Roo.data.Record.create(recordType) : recordType;
19951 Roo.data.DataReader.prototype = {
19953 * Create an empty record
19954 * @param {Object} data (optional) - overlay some values
19955 * @return {Roo.data.Record} record created.
19957 newRow : function(d) {
19959 this.recordType.prototype.fields.each(function(c) {
19961 case 'int' : da[c.name] = 0; break;
19962 case 'date' : da[c.name] = new Date(); break;
19963 case 'float' : da[c.name] = 0.0; break;
19964 case 'boolean' : da[c.name] = false; break;
19965 default : da[c.name] = ""; break;
19969 return new this.recordType(Roo.apply(da, d));
19974 * Ext JS Library 1.1.1
19975 * Copyright(c) 2006-2007, Ext JS, LLC.
19977 * Originally Released Under LGPL - original licence link has changed is not relivant.
19980 * <script type="text/javascript">
19984 * @class Roo.data.DataProxy
19985 * @extends Roo.data.Observable
19986 * This class is an abstract base class for implementations which provide retrieval of
19987 * unformatted data objects.<br>
19989 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19990 * (of the appropriate type which knows how to parse the data object) to provide a block of
19991 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19993 * Custom implementations must implement the load method as described in
19994 * {@link Roo.data.HttpProxy#load}.
19996 Roo.data.DataProxy = function(){
19999 * @event beforeload
20000 * Fires before a network request is made to retrieve a data object.
20001 * @param {Object} This DataProxy object.
20002 * @param {Object} params The params parameter to the load function.
20007 * Fires before the load method's callback is called.
20008 * @param {Object} This DataProxy object.
20009 * @param {Object} o The data object.
20010 * @param {Object} arg The callback argument object passed to the load function.
20014 * @event loadexception
20015 * Fires if an Exception occurs during data retrieval.
20016 * @param {Object} This DataProxy object.
20017 * @param {Object} o The data object.
20018 * @param {Object} arg The callback argument object passed to the load function.
20019 * @param {Object} e The Exception.
20021 loadexception : true
20023 Roo.data.DataProxy.superclass.constructor.call(this);
20026 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20029 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20033 * Ext JS Library 1.1.1
20034 * Copyright(c) 2006-2007, Ext JS, LLC.
20036 * Originally Released Under LGPL - original licence link has changed is not relivant.
20039 * <script type="text/javascript">
20042 * @class Roo.data.MemoryProxy
20043 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20044 * to the Reader when its load method is called.
20046 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20048 Roo.data.MemoryProxy = function(data){
20052 Roo.data.MemoryProxy.superclass.constructor.call(this);
20056 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20058 * Load data from the requested source (in this case an in-memory
20059 * data object passed to the constructor), read the data object into
20060 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20061 * process that block using the passed callback.
20062 * @param {Object} params This parameter is not used by the MemoryProxy class.
20063 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20064 * object into a block of Roo.data.Records.
20065 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20066 * The function must be passed <ul>
20067 * <li>The Record block object</li>
20068 * <li>The "arg" argument from the load function</li>
20069 * <li>A boolean success indicator</li>
20071 * @param {Object} scope The scope in which to call the callback
20072 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20074 load : function(params, reader, callback, scope, arg){
20075 params = params || {};
20078 result = reader.readRecords(this.data);
20080 this.fireEvent("loadexception", this, arg, null, e);
20081 callback.call(scope, null, arg, false);
20084 callback.call(scope, result, arg, true);
20088 update : function(params, records){
20093 * Ext JS Library 1.1.1
20094 * Copyright(c) 2006-2007, Ext JS, LLC.
20096 * Originally Released Under LGPL - original licence link has changed is not relivant.
20099 * <script type="text/javascript">
20102 * @class Roo.data.HttpProxy
20103 * @extends Roo.data.DataProxy
20104 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20105 * configured to reference a certain URL.<br><br>
20107 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20108 * from which the running page was served.<br><br>
20110 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20112 * Be aware that to enable the browser to parse an XML document, the server must set
20113 * the Content-Type header in the HTTP response to "text/xml".
20115 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20116 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20117 * will be used to make the request.
20119 Roo.data.HttpProxy = function(conn){
20120 Roo.data.HttpProxy.superclass.constructor.call(this);
20121 // is conn a conn config or a real conn?
20123 this.useAjax = !conn || !conn.events;
20127 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20128 // thse are take from connection...
20131 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20134 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20135 * extra parameters to each request made by this object. (defaults to undefined)
20138 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20139 * to each request made by this object. (defaults to undefined)
20142 * @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)
20145 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20148 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20154 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20158 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20159 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20160 * a finer-grained basis than the DataProxy events.
20162 getConnection : function(){
20163 return this.useAjax ? Roo.Ajax : this.conn;
20167 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20168 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20169 * process that block using the passed callback.
20170 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20171 * for the request to the remote server.
20172 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20173 * object into a block of Roo.data.Records.
20174 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20175 * The function must be passed <ul>
20176 * <li>The Record block object</li>
20177 * <li>The "arg" argument from the load function</li>
20178 * <li>A boolean success indicator</li>
20180 * @param {Object} scope The scope in which to call the callback
20181 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20183 load : function(params, reader, callback, scope, arg){
20184 if(this.fireEvent("beforeload", this, params) !== false){
20186 params : params || {},
20188 callback : callback,
20193 callback : this.loadResponse,
20197 Roo.applyIf(o, this.conn);
20198 if(this.activeRequest){
20199 Roo.Ajax.abort(this.activeRequest);
20201 this.activeRequest = Roo.Ajax.request(o);
20203 this.conn.request(o);
20206 callback.call(scope||this, null, arg, false);
20211 loadResponse : function(o, success, response){
20212 delete this.activeRequest;
20214 this.fireEvent("loadexception", this, o, response);
20215 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20220 result = o.reader.read(response);
20222 this.fireEvent("loadexception", this, o, response, e);
20223 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20227 this.fireEvent("load", this, o, o.request.arg);
20228 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20232 update : function(dataSet){
20237 updateResponse : function(dataSet){
20242 * Ext JS Library 1.1.1
20243 * Copyright(c) 2006-2007, Ext JS, LLC.
20245 * Originally Released Under LGPL - original licence link has changed is not relivant.
20248 * <script type="text/javascript">
20252 * @class Roo.data.ScriptTagProxy
20253 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20254 * other than the originating domain of the running page.<br><br>
20256 * <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
20257 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20259 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20260 * source code that is used as the source inside a <script> tag.<br><br>
20262 * In order for the browser to process the returned data, the server must wrap the data object
20263 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20264 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20265 * depending on whether the callback name was passed:
20268 boolean scriptTag = false;
20269 String cb = request.getParameter("callback");
20272 response.setContentType("text/javascript");
20274 response.setContentType("application/x-json");
20276 Writer out = response.getWriter();
20278 out.write(cb + "(");
20280 out.print(dataBlock.toJsonString());
20287 * @param {Object} config A configuration object.
20289 Roo.data.ScriptTagProxy = function(config){
20290 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20291 Roo.apply(this, config);
20292 this.head = document.getElementsByTagName("head")[0];
20295 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20297 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20299 * @cfg {String} url The URL from which to request the data object.
20302 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20306 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20307 * the server the name of the callback function set up by the load call to process the returned data object.
20308 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20309 * javascript output which calls this named function passing the data object as its only parameter.
20311 callbackParam : "callback",
20313 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20314 * name to the request.
20319 * Load data from the configured URL, read the data object into
20320 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20321 * process that block using the passed callback.
20322 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20323 * for the request to the remote server.
20324 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20325 * object into a block of Roo.data.Records.
20326 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20327 * The function must be passed <ul>
20328 * <li>The Record block object</li>
20329 * <li>The "arg" argument from the load function</li>
20330 * <li>A boolean success indicator</li>
20332 * @param {Object} scope The scope in which to call the callback
20333 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20335 load : function(params, reader, callback, scope, arg){
20336 if(this.fireEvent("beforeload", this, params) !== false){
20338 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20340 var url = this.url;
20341 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20343 url += "&_dc=" + (new Date().getTime());
20345 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20348 cb : "stcCallback"+transId,
20349 scriptId : "stcScript"+transId,
20353 callback : callback,
20359 window[trans.cb] = function(o){
20360 conn.handleResponse(o, trans);
20363 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20365 if(this.autoAbort !== false){
20369 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20371 var script = document.createElement("script");
20372 script.setAttribute("src", url);
20373 script.setAttribute("type", "text/javascript");
20374 script.setAttribute("id", trans.scriptId);
20375 this.head.appendChild(script);
20377 this.trans = trans;
20379 callback.call(scope||this, null, arg, false);
20384 isLoading : function(){
20385 return this.trans ? true : false;
20389 * Abort the current server request.
20391 abort : function(){
20392 if(this.isLoading()){
20393 this.destroyTrans(this.trans);
20398 destroyTrans : function(trans, isLoaded){
20399 this.head.removeChild(document.getElementById(trans.scriptId));
20400 clearTimeout(trans.timeoutId);
20402 window[trans.cb] = undefined;
20404 delete window[trans.cb];
20407 // if hasn't been loaded, wait for load to remove it to prevent script error
20408 window[trans.cb] = function(){
20409 window[trans.cb] = undefined;
20411 delete window[trans.cb];
20418 handleResponse : function(o, trans){
20419 this.trans = false;
20420 this.destroyTrans(trans, true);
20423 result = trans.reader.readRecords(o);
20425 this.fireEvent("loadexception", this, o, trans.arg, e);
20426 trans.callback.call(trans.scope||window, null, trans.arg, false);
20429 this.fireEvent("load", this, o, trans.arg);
20430 trans.callback.call(trans.scope||window, result, trans.arg, true);
20434 handleFailure : function(trans){
20435 this.trans = false;
20436 this.destroyTrans(trans, false);
20437 this.fireEvent("loadexception", this, null, trans.arg);
20438 trans.callback.call(trans.scope||window, null, trans.arg, false);
20442 * Ext JS Library 1.1.1
20443 * Copyright(c) 2006-2007, Ext JS, LLC.
20445 * Originally Released Under LGPL - original licence link has changed is not relivant.
20448 * <script type="text/javascript">
20452 * @class Roo.data.JsonReader
20453 * @extends Roo.data.DataReader
20454 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20455 * based on mappings in a provided Roo.data.Record constructor.
20457 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20458 * in the reply previously.
20463 var RecordDef = Roo.data.Record.create([
20464 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20465 {name: 'occupation'} // This field will use "occupation" as the mapping.
20467 var myReader = new Roo.data.JsonReader({
20468 totalProperty: "results", // The property which contains the total dataset size (optional)
20469 root: "rows", // The property which contains an Array of row objects
20470 id: "id" // The property within each row object that provides an ID for the record (optional)
20474 * This would consume a JSON file like this:
20476 { 'results': 2, 'rows': [
20477 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20478 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20481 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20482 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20483 * paged from the remote server.
20484 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20485 * @cfg {String} root name of the property which contains the Array of row objects.
20486 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20488 * Create a new JsonReader
20489 * @param {Object} meta Metadata configuration options
20490 * @param {Object} recordType Either an Array of field definition objects,
20491 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20493 Roo.data.JsonReader = function(meta, recordType){
20496 // set some defaults:
20497 Roo.applyIf(meta, {
20498 totalProperty: 'total',
20499 successProperty : 'success',
20504 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20506 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20509 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20510 * Used by Store query builder to append _requestMeta to params.
20513 metaFromRemote : false,
20515 * This method is only used by a DataProxy which has retrieved data from a remote server.
20516 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20517 * @return {Object} data A data block which is used by an Roo.data.Store object as
20518 * a cache of Roo.data.Records.
20520 read : function(response){
20521 var json = response.responseText;
20523 var o = /* eval:var:o */ eval("("+json+")");
20525 throw {message: "JsonReader.read: Json object not found"};
20531 this.metaFromRemote = true;
20532 this.meta = o.metaData;
20533 this.recordType = Roo.data.Record.create(o.metaData.fields);
20534 this.onMetaChange(this.meta, this.recordType, o);
20536 return this.readRecords(o);
20539 // private function a store will implement
20540 onMetaChange : function(meta, recordType, o){
20547 simpleAccess: function(obj, subsc) {
20554 getJsonAccessor: function(){
20556 return function(expr) {
20558 return(re.test(expr))
20559 ? new Function("obj", "return obj." + expr)
20564 return Roo.emptyFn;
20569 * Create a data block containing Roo.data.Records from an XML document.
20570 * @param {Object} o An object which contains an Array of row objects in the property specified
20571 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20572 * which contains the total size of the dataset.
20573 * @return {Object} data A data block which is used by an Roo.data.Store object as
20574 * a cache of Roo.data.Records.
20576 readRecords : function(o){
20578 * After any data loads, the raw JSON data is available for further custom processing.
20582 var s = this.meta, Record = this.recordType,
20583 f = Record.prototype.fields, fi = f.items, fl = f.length;
20585 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20587 if(s.totalProperty) {
20588 this.getTotal = this.getJsonAccessor(s.totalProperty);
20590 if(s.successProperty) {
20591 this.getSuccess = this.getJsonAccessor(s.successProperty);
20593 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20595 var g = this.getJsonAccessor(s.id);
20596 this.getId = function(rec) {
20598 return (r === undefined || r === "") ? null : r;
20601 this.getId = function(){return null;};
20604 for(var jj = 0; jj < fl; jj++){
20606 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20607 this.ef[jj] = this.getJsonAccessor(map);
20611 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20612 if(s.totalProperty){
20613 var vt = parseInt(this.getTotal(o), 10);
20618 if(s.successProperty){
20619 var vs = this.getSuccess(o);
20620 if(vs === false || vs === 'false'){
20625 for(var i = 0; i < c; i++){
20628 var id = this.getId(n);
20629 for(var j = 0; j < fl; j++){
20631 var v = this.ef[j](n);
20633 Roo.log('missing convert for ' + f.name);
20637 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20639 var record = new Record(values, id);
20641 records[i] = record;
20646 totalRecords : totalRecords
20651 * Ext JS Library 1.1.1
20652 * Copyright(c) 2006-2007, Ext JS, LLC.
20654 * Originally Released Under LGPL - original licence link has changed is not relivant.
20657 * <script type="text/javascript">
20661 * @class Roo.data.XmlReader
20662 * @extends Roo.data.DataReader
20663 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20664 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20666 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20667 * header in the HTTP response must be set to "text/xml".</em>
20671 var RecordDef = Roo.data.Record.create([
20672 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20673 {name: 'occupation'} // This field will use "occupation" as the mapping.
20675 var myReader = new Roo.data.XmlReader({
20676 totalRecords: "results", // The element which contains the total dataset size (optional)
20677 record: "row", // The repeated element which contains row information
20678 id: "id" // The element within the row that provides an ID for the record (optional)
20682 * This would consume an XML file like this:
20686 <results>2</results>
20689 <name>Bill</name>
20690 <occupation>Gardener</occupation>
20694 <name>Ben</name>
20695 <occupation>Horticulturalist</occupation>
20699 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20700 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20701 * paged from the remote server.
20702 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20703 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20704 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20705 * a record identifier value.
20707 * Create a new XmlReader
20708 * @param {Object} meta Metadata configuration options
20709 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20710 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20711 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20713 Roo.data.XmlReader = function(meta, recordType){
20715 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20717 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20719 * This method is only used by a DataProxy which has retrieved data from a remote server.
20720 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20721 * to contain a method called 'responseXML' that returns an XML document object.
20722 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20723 * a cache of Roo.data.Records.
20725 read : function(response){
20726 var doc = response.responseXML;
20728 throw {message: "XmlReader.read: XML Document not available"};
20730 return this.readRecords(doc);
20734 * Create a data block containing Roo.data.Records from an XML document.
20735 * @param {Object} doc A parsed XML document.
20736 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20737 * a cache of Roo.data.Records.
20739 readRecords : function(doc){
20741 * After any data loads/reads, the raw XML Document is available for further custom processing.
20742 * @type XMLDocument
20744 this.xmlData = doc;
20745 var root = doc.documentElement || doc;
20746 var q = Roo.DomQuery;
20747 var recordType = this.recordType, fields = recordType.prototype.fields;
20748 var sid = this.meta.id;
20749 var totalRecords = 0, success = true;
20750 if(this.meta.totalRecords){
20751 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20754 if(this.meta.success){
20755 var sv = q.selectValue(this.meta.success, root, true);
20756 success = sv !== false && sv !== 'false';
20759 var ns = q.select(this.meta.record, root);
20760 for(var i = 0, len = ns.length; i < len; i++) {
20763 var id = sid ? q.selectValue(sid, n) : undefined;
20764 for(var j = 0, jlen = fields.length; j < jlen; j++){
20765 var f = fields.items[j];
20766 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20768 values[f.name] = v;
20770 var record = new recordType(values, id);
20772 records[records.length] = record;
20778 totalRecords : totalRecords || records.length
20783 * Ext JS Library 1.1.1
20784 * Copyright(c) 2006-2007, Ext JS, LLC.
20786 * Originally Released Under LGPL - original licence link has changed is not relivant.
20789 * <script type="text/javascript">
20793 * @class Roo.data.ArrayReader
20794 * @extends Roo.data.DataReader
20795 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20796 * Each element of that Array represents a row of data fields. The
20797 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20798 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20802 var RecordDef = Roo.data.Record.create([
20803 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20804 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20806 var myReader = new Roo.data.ArrayReader({
20807 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20811 * This would consume an Array like this:
20813 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20815 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20817 * Create a new JsonReader
20818 * @param {Object} meta Metadata configuration options.
20819 * @param {Object} recordType Either an Array of field definition objects
20820 * as specified to {@link Roo.data.Record#create},
20821 * or an {@link Roo.data.Record} object
20822 * created using {@link Roo.data.Record#create}.
20824 Roo.data.ArrayReader = function(meta, recordType){
20825 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20828 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20830 * Create a data block containing Roo.data.Records from an XML document.
20831 * @param {Object} o An Array of row objects which represents the dataset.
20832 * @return {Object} data A data block which is used by an Roo.data.Store object as
20833 * a cache of Roo.data.Records.
20835 readRecords : function(o){
20836 var sid = this.meta ? this.meta.id : null;
20837 var recordType = this.recordType, fields = recordType.prototype.fields;
20840 for(var i = 0; i < root.length; i++){
20843 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20844 for(var j = 0, jlen = fields.length; j < jlen; j++){
20845 var f = fields.items[j];
20846 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20847 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20849 values[f.name] = v;
20851 var record = new recordType(values, id);
20853 records[records.length] = record;
20857 totalRecords : records.length
20862 * Ext JS Library 1.1.1
20863 * Copyright(c) 2006-2007, Ext JS, LLC.
20865 * Originally Released Under LGPL - original licence link has changed is not relivant.
20868 * <script type="text/javascript">
20873 * @class Roo.data.Tree
20874 * @extends Roo.util.Observable
20875 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20876 * in the tree have most standard DOM functionality.
20878 * @param {Node} root (optional) The root node
20880 Roo.data.Tree = function(root){
20881 this.nodeHash = {};
20883 * The root node for this tree
20888 this.setRootNode(root);
20893 * Fires when a new child node is appended to a node in this tree.
20894 * @param {Tree} tree The owner tree
20895 * @param {Node} parent The parent node
20896 * @param {Node} node The newly appended node
20897 * @param {Number} index The index of the newly appended node
20902 * Fires when a child node is removed from a node in this tree.
20903 * @param {Tree} tree The owner tree
20904 * @param {Node} parent The parent node
20905 * @param {Node} node The child node removed
20910 * Fires when a node is moved to a new location in the tree
20911 * @param {Tree} tree The owner tree
20912 * @param {Node} node The node moved
20913 * @param {Node} oldParent The old parent of this node
20914 * @param {Node} newParent The new parent of this node
20915 * @param {Number} index The index it was moved to
20920 * Fires when a new child node is inserted in a node in this tree.
20921 * @param {Tree} tree The owner tree
20922 * @param {Node} parent The parent node
20923 * @param {Node} node The child node inserted
20924 * @param {Node} refNode The child node the node was inserted before
20928 * @event beforeappend
20929 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20930 * @param {Tree} tree The owner tree
20931 * @param {Node} parent The parent node
20932 * @param {Node} node The child node to be appended
20934 "beforeappend" : true,
20936 * @event beforeremove
20937 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20938 * @param {Tree} tree The owner tree
20939 * @param {Node} parent The parent node
20940 * @param {Node} node The child node to be removed
20942 "beforeremove" : true,
20944 * @event beforemove
20945 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20946 * @param {Tree} tree The owner tree
20947 * @param {Node} node The node being moved
20948 * @param {Node} oldParent The parent of the node
20949 * @param {Node} newParent The new parent the node is moving to
20950 * @param {Number} index The index it is being moved to
20952 "beforemove" : true,
20954 * @event beforeinsert
20955 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20956 * @param {Tree} tree The owner tree
20957 * @param {Node} parent The parent node
20958 * @param {Node} node The child node to be inserted
20959 * @param {Node} refNode The child node the node is being inserted before
20961 "beforeinsert" : true
20964 Roo.data.Tree.superclass.constructor.call(this);
20967 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20968 pathSeparator: "/",
20970 proxyNodeEvent : function(){
20971 return this.fireEvent.apply(this, arguments);
20975 * Returns the root node for this tree.
20978 getRootNode : function(){
20983 * Sets the root node for this tree.
20984 * @param {Node} node
20987 setRootNode : function(node){
20989 node.ownerTree = this;
20990 node.isRoot = true;
20991 this.registerNode(node);
20996 * Gets a node in this tree by its id.
20997 * @param {String} id
21000 getNodeById : function(id){
21001 return this.nodeHash[id];
21004 registerNode : function(node){
21005 this.nodeHash[node.id] = node;
21008 unregisterNode : function(node){
21009 delete this.nodeHash[node.id];
21012 toString : function(){
21013 return "[Tree"+(this.id?" "+this.id:"")+"]";
21018 * @class Roo.data.Node
21019 * @extends Roo.util.Observable
21020 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21021 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21023 * @param {Object} attributes The attributes/config for the node
21025 Roo.data.Node = function(attributes){
21027 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21030 this.attributes = attributes || {};
21031 this.leaf = this.attributes.leaf;
21033 * The node id. @type String
21035 this.id = this.attributes.id;
21037 this.id = Roo.id(null, "ynode-");
21038 this.attributes.id = this.id;
21041 * All child nodes of this node. @type Array
21043 this.childNodes = [];
21044 if(!this.childNodes.indexOf){ // indexOf is a must
21045 this.childNodes.indexOf = function(o){
21046 for(var i = 0, len = this.length; i < len; i++){
21055 * The parent node for this node. @type Node
21057 this.parentNode = null;
21059 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21061 this.firstChild = null;
21063 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21065 this.lastChild = null;
21067 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21069 this.previousSibling = null;
21071 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21073 this.nextSibling = null;
21078 * Fires when a new child node is appended
21079 * @param {Tree} tree The owner tree
21080 * @param {Node} this This node
21081 * @param {Node} node The newly appended node
21082 * @param {Number} index The index of the newly appended node
21087 * Fires when a child node is removed
21088 * @param {Tree} tree The owner tree
21089 * @param {Node} this This node
21090 * @param {Node} node The removed node
21095 * Fires when this node is moved to a new location in the tree
21096 * @param {Tree} tree The owner tree
21097 * @param {Node} this This node
21098 * @param {Node} oldParent The old parent of this node
21099 * @param {Node} newParent The new parent of this node
21100 * @param {Number} index The index it was moved to
21105 * Fires when a new child node is inserted.
21106 * @param {Tree} tree The owner tree
21107 * @param {Node} this This node
21108 * @param {Node} node The child node inserted
21109 * @param {Node} refNode The child node the node was inserted before
21113 * @event beforeappend
21114 * Fires before a new child is appended, return false to cancel the append.
21115 * @param {Tree} tree The owner tree
21116 * @param {Node} this This node
21117 * @param {Node} node The child node to be appended
21119 "beforeappend" : true,
21121 * @event beforeremove
21122 * Fires before a child is removed, return false to cancel the remove.
21123 * @param {Tree} tree The owner tree
21124 * @param {Node} this This node
21125 * @param {Node} node The child node to be removed
21127 "beforeremove" : true,
21129 * @event beforemove
21130 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21131 * @param {Tree} tree The owner tree
21132 * @param {Node} this This node
21133 * @param {Node} oldParent The parent of this node
21134 * @param {Node} newParent The new parent this node is moving to
21135 * @param {Number} index The index it is being moved to
21137 "beforemove" : true,
21139 * @event beforeinsert
21140 * Fires before a new child is inserted, return false to cancel the insert.
21141 * @param {Tree} tree The owner tree
21142 * @param {Node} this This node
21143 * @param {Node} node The child node to be inserted
21144 * @param {Node} refNode The child node the node is being inserted before
21146 "beforeinsert" : true
21148 this.listeners = this.attributes.listeners;
21149 Roo.data.Node.superclass.constructor.call(this);
21152 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21153 fireEvent : function(evtName){
21154 // first do standard event for this node
21155 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21158 // then bubble it up to the tree if the event wasn't cancelled
21159 var ot = this.getOwnerTree();
21161 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21169 * Returns true if this node is a leaf
21170 * @return {Boolean}
21172 isLeaf : function(){
21173 return this.leaf === true;
21177 setFirstChild : function(node){
21178 this.firstChild = node;
21182 setLastChild : function(node){
21183 this.lastChild = node;
21188 * Returns true if this node is the last child of its parent
21189 * @return {Boolean}
21191 isLast : function(){
21192 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21196 * Returns true if this node is the first child of its parent
21197 * @return {Boolean}
21199 isFirst : function(){
21200 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21203 hasChildNodes : function(){
21204 return !this.isLeaf() && this.childNodes.length > 0;
21208 * Insert node(s) as the last child node of this node.
21209 * @param {Node/Array} node The node or Array of nodes to append
21210 * @return {Node} The appended node if single append, or null if an array was passed
21212 appendChild : function(node){
21214 if(node instanceof Array){
21216 }else if(arguments.length > 1){
21219 // if passed an array or multiple args do them one by one
21221 for(var i = 0, len = multi.length; i < len; i++) {
21222 this.appendChild(multi[i]);
21225 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21228 var index = this.childNodes.length;
21229 var oldParent = node.parentNode;
21230 // it's a move, make sure we move it cleanly
21232 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21235 oldParent.removeChild(node);
21237 index = this.childNodes.length;
21239 this.setFirstChild(node);
21241 this.childNodes.push(node);
21242 node.parentNode = this;
21243 var ps = this.childNodes[index-1];
21245 node.previousSibling = ps;
21246 ps.nextSibling = node;
21248 node.previousSibling = null;
21250 node.nextSibling = null;
21251 this.setLastChild(node);
21252 node.setOwnerTree(this.getOwnerTree());
21253 this.fireEvent("append", this.ownerTree, this, node, index);
21255 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21262 * Removes a child node from this node.
21263 * @param {Node} node The node to remove
21264 * @return {Node} The removed node
21266 removeChild : function(node){
21267 var index = this.childNodes.indexOf(node);
21271 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21275 // remove it from childNodes collection
21276 this.childNodes.splice(index, 1);
21279 if(node.previousSibling){
21280 node.previousSibling.nextSibling = node.nextSibling;
21282 if(node.nextSibling){
21283 node.nextSibling.previousSibling = node.previousSibling;
21286 // update child refs
21287 if(this.firstChild == node){
21288 this.setFirstChild(node.nextSibling);
21290 if(this.lastChild == node){
21291 this.setLastChild(node.previousSibling);
21294 node.setOwnerTree(null);
21295 // clear any references from the node
21296 node.parentNode = null;
21297 node.previousSibling = null;
21298 node.nextSibling = null;
21299 this.fireEvent("remove", this.ownerTree, this, node);
21304 * Inserts the first node before the second node in this nodes childNodes collection.
21305 * @param {Node} node The node to insert
21306 * @param {Node} refNode The node to insert before (if null the node is appended)
21307 * @return {Node} The inserted node
21309 insertBefore : function(node, refNode){
21310 if(!refNode){ // like standard Dom, refNode can be null for append
21311 return this.appendChild(node);
21314 if(node == refNode){
21318 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21321 var index = this.childNodes.indexOf(refNode);
21322 var oldParent = node.parentNode;
21323 var refIndex = index;
21325 // when moving internally, indexes will change after remove
21326 if(oldParent == this && this.childNodes.indexOf(node) < index){
21330 // it's a move, make sure we move it cleanly
21332 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21335 oldParent.removeChild(node);
21338 this.setFirstChild(node);
21340 this.childNodes.splice(refIndex, 0, node);
21341 node.parentNode = this;
21342 var ps = this.childNodes[refIndex-1];
21344 node.previousSibling = ps;
21345 ps.nextSibling = node;
21347 node.previousSibling = null;
21349 node.nextSibling = refNode;
21350 refNode.previousSibling = node;
21351 node.setOwnerTree(this.getOwnerTree());
21352 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21354 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21360 * Returns the child node at the specified index.
21361 * @param {Number} index
21364 item : function(index){
21365 return this.childNodes[index];
21369 * Replaces one child node in this node with another.
21370 * @param {Node} newChild The replacement node
21371 * @param {Node} oldChild The node to replace
21372 * @return {Node} The replaced node
21374 replaceChild : function(newChild, oldChild){
21375 this.insertBefore(newChild, oldChild);
21376 this.removeChild(oldChild);
21381 * Returns the index of a child node
21382 * @param {Node} node
21383 * @return {Number} The index of the node or -1 if it was not found
21385 indexOf : function(child){
21386 return this.childNodes.indexOf(child);
21390 * Returns the tree this node is in.
21393 getOwnerTree : function(){
21394 // if it doesn't have one, look for one
21395 if(!this.ownerTree){
21399 this.ownerTree = p.ownerTree;
21405 return this.ownerTree;
21409 * Returns depth of this node (the root node has a depth of 0)
21412 getDepth : function(){
21415 while(p.parentNode){
21423 setOwnerTree : function(tree){
21424 // if it's move, we need to update everyone
21425 if(tree != this.ownerTree){
21426 if(this.ownerTree){
21427 this.ownerTree.unregisterNode(this);
21429 this.ownerTree = tree;
21430 var cs = this.childNodes;
21431 for(var i = 0, len = cs.length; i < len; i++) {
21432 cs[i].setOwnerTree(tree);
21435 tree.registerNode(this);
21441 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21442 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21443 * @return {String} The path
21445 getPath : function(attr){
21446 attr = attr || "id";
21447 var p = this.parentNode;
21448 var b = [this.attributes[attr]];
21450 b.unshift(p.attributes[attr]);
21453 var sep = this.getOwnerTree().pathSeparator;
21454 return sep + b.join(sep);
21458 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21459 * function call will be the scope provided or the current node. The arguments to the function
21460 * will be the args provided or the current node. If the function returns false at any point,
21461 * the bubble is stopped.
21462 * @param {Function} fn The function to call
21463 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21464 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21466 bubble : function(fn, scope, args){
21469 if(fn.call(scope || p, args || p) === false){
21477 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21478 * function call will be the scope provided or the current node. The arguments to the function
21479 * will be the args provided or the current node. If the function returns false at any point,
21480 * the cascade is stopped on that branch.
21481 * @param {Function} fn The function to call
21482 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21483 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21485 cascade : function(fn, scope, args){
21486 if(fn.call(scope || this, args || this) !== false){
21487 var cs = this.childNodes;
21488 for(var i = 0, len = cs.length; i < len; i++) {
21489 cs[i].cascade(fn, scope, args);
21495 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21496 * function call will be the scope provided or the current node. The arguments to the function
21497 * will be the args provided or the current node. If the function returns false at any point,
21498 * the iteration stops.
21499 * @param {Function} fn The function to call
21500 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21501 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21503 eachChild : function(fn, scope, args){
21504 var cs = this.childNodes;
21505 for(var i = 0, len = cs.length; i < len; i++) {
21506 if(fn.call(scope || this, args || cs[i]) === false){
21513 * Finds the first child that has the attribute with the specified value.
21514 * @param {String} attribute The attribute name
21515 * @param {Mixed} value The value to search for
21516 * @return {Node} The found child or null if none was found
21518 findChild : function(attribute, value){
21519 var cs = this.childNodes;
21520 for(var i = 0, len = cs.length; i < len; i++) {
21521 if(cs[i].attributes[attribute] == value){
21529 * Finds the first child by a custom function. The child matches if the function passed
21531 * @param {Function} fn
21532 * @param {Object} scope (optional)
21533 * @return {Node} The found child or null if none was found
21535 findChildBy : function(fn, scope){
21536 var cs = this.childNodes;
21537 for(var i = 0, len = cs.length; i < len; i++) {
21538 if(fn.call(scope||cs[i], cs[i]) === true){
21546 * Sorts this nodes children using the supplied sort function
21547 * @param {Function} fn
21548 * @param {Object} scope (optional)
21550 sort : function(fn, scope){
21551 var cs = this.childNodes;
21552 var len = cs.length;
21554 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21556 for(var i = 0; i < len; i++){
21558 n.previousSibling = cs[i-1];
21559 n.nextSibling = cs[i+1];
21561 this.setFirstChild(n);
21564 this.setLastChild(n);
21571 * Returns true if this node is an ancestor (at any point) of the passed node.
21572 * @param {Node} node
21573 * @return {Boolean}
21575 contains : function(node){
21576 return node.isAncestor(this);
21580 * Returns true if the passed node is an ancestor (at any point) of this node.
21581 * @param {Node} node
21582 * @return {Boolean}
21584 isAncestor : function(node){
21585 var p = this.parentNode;
21595 toString : function(){
21596 return "[Node"+(this.id?" "+this.id:"")+"]";
21600 * Ext JS Library 1.1.1
21601 * Copyright(c) 2006-2007, Ext JS, LLC.
21603 * Originally Released Under LGPL - original licence link has changed is not relivant.
21606 * <script type="text/javascript">
21611 * @class Roo.ComponentMgr
21612 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21615 Roo.ComponentMgr = function(){
21616 var all = new Roo.util.MixedCollection();
21620 * Registers a component.
21621 * @param {Roo.Component} c The component
21623 register : function(c){
21628 * Unregisters a component.
21629 * @param {Roo.Component} c The component
21631 unregister : function(c){
21636 * Returns a component by id
21637 * @param {String} id The component id
21639 get : function(id){
21640 return all.get(id);
21644 * Registers a function that will be called when a specified component is added to ComponentMgr
21645 * @param {String} id The component id
21646 * @param {Funtction} fn The callback function
21647 * @param {Object} scope The scope of the callback
21649 onAvailable : function(id, fn, scope){
21650 all.on("add", function(index, o){
21652 fn.call(scope || o, o);
21653 all.un("add", fn, scope);
21660 * Ext JS Library 1.1.1
21661 * Copyright(c) 2006-2007, Ext JS, LLC.
21663 * Originally Released Under LGPL - original licence link has changed is not relivant.
21666 * <script type="text/javascript">
21670 * @class Roo.Component
21671 * @extends Roo.util.Observable
21672 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21673 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21674 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21675 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21676 * All visual components (widgets) that require rendering into a layout should subclass Component.
21678 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21679 * 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
21680 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21682 Roo.Component = function(config){
21683 config = config || {};
21684 if(config.tagName || config.dom || typeof config == "string"){ // element object
21685 config = {el: config, id: config.id || config};
21687 this.initialConfig = config;
21689 Roo.apply(this, config);
21693 * Fires after the component is disabled.
21694 * @param {Roo.Component} this
21699 * Fires after the component is enabled.
21700 * @param {Roo.Component} this
21704 * @event beforeshow
21705 * Fires before the component is shown. Return false to stop the show.
21706 * @param {Roo.Component} this
21711 * Fires after the component is shown.
21712 * @param {Roo.Component} this
21716 * @event beforehide
21717 * Fires before the component is hidden. Return false to stop the hide.
21718 * @param {Roo.Component} this
21723 * Fires after the component is hidden.
21724 * @param {Roo.Component} this
21728 * @event beforerender
21729 * Fires before the component is rendered. Return false to stop the render.
21730 * @param {Roo.Component} this
21732 beforerender : true,
21735 * Fires after the component is rendered.
21736 * @param {Roo.Component} this
21740 * @event beforedestroy
21741 * Fires before the component is destroyed. Return false to stop the destroy.
21742 * @param {Roo.Component} this
21744 beforedestroy : true,
21747 * Fires after the component is destroyed.
21748 * @param {Roo.Component} this
21753 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21755 Roo.ComponentMgr.register(this);
21756 Roo.Component.superclass.constructor.call(this);
21757 this.initComponent();
21758 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21759 this.render(this.renderTo);
21760 delete this.renderTo;
21765 Roo.Component.AUTO_ID = 1000;
21767 Roo.extend(Roo.Component, Roo.util.Observable, {
21769 * @property {Boolean} hidden
21770 * true if this component is hidden. Read-only.
21774 * true if this component is disabled. Read-only.
21778 * true if this component has been rendered. Read-only.
21782 /** @cfg {String} disableClass
21783 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21785 disabledClass : "x-item-disabled",
21786 /** @cfg {Boolean} allowDomMove
21787 * Whether the component can move the Dom node when rendering (defaults to true).
21789 allowDomMove : true,
21790 /** @cfg {String} hideMode
21791 * How this component should hidden. Supported values are
21792 * "visibility" (css visibility), "offsets" (negative offset position) and
21793 * "display" (css display) - defaults to "display".
21795 hideMode: 'display',
21798 ctype : "Roo.Component",
21800 /** @cfg {String} actionMode
21801 * which property holds the element that used for hide() / show() / disable() / enable()
21807 getActionEl : function(){
21808 return this[this.actionMode];
21811 initComponent : Roo.emptyFn,
21813 * If this is a lazy rendering component, render it to its container element.
21814 * @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.
21816 render : function(container, position){
21817 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21818 if(!container && this.el){
21819 this.el = Roo.get(this.el);
21820 container = this.el.dom.parentNode;
21821 this.allowDomMove = false;
21823 this.container = Roo.get(container);
21824 this.rendered = true;
21825 if(position !== undefined){
21826 if(typeof position == 'number'){
21827 position = this.container.dom.childNodes[position];
21829 position = Roo.getDom(position);
21832 this.onRender(this.container, position || null);
21834 this.el.addClass(this.cls);
21838 this.el.applyStyles(this.style);
21841 this.fireEvent("render", this);
21842 this.afterRender(this.container);
21854 // default function is not really useful
21855 onRender : function(ct, position){
21857 this.el = Roo.get(this.el);
21858 if(this.allowDomMove !== false){
21859 ct.dom.insertBefore(this.el.dom, position);
21865 getAutoCreate : function(){
21866 var cfg = typeof this.autoCreate == "object" ?
21867 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21868 if(this.id && !cfg.id){
21875 afterRender : Roo.emptyFn,
21878 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21879 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21881 destroy : function(){
21882 if(this.fireEvent("beforedestroy", this) !== false){
21883 this.purgeListeners();
21884 this.beforeDestroy();
21886 this.el.removeAllListeners();
21888 if(this.actionMode == "container"){
21889 this.container.remove();
21893 Roo.ComponentMgr.unregister(this);
21894 this.fireEvent("destroy", this);
21899 beforeDestroy : function(){
21904 onDestroy : function(){
21909 * Returns the underlying {@link Roo.Element}.
21910 * @return {Roo.Element} The element
21912 getEl : function(){
21917 * Returns the id of this component.
21920 getId : function(){
21925 * Try to focus this component.
21926 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21927 * @return {Roo.Component} this
21929 focus : function(selectText){
21932 if(selectText === true){
21933 this.el.dom.select();
21948 * Disable this component.
21949 * @return {Roo.Component} this
21951 disable : function(){
21955 this.disabled = true;
21956 this.fireEvent("disable", this);
21961 onDisable : function(){
21962 this.getActionEl().addClass(this.disabledClass);
21963 this.el.dom.disabled = true;
21967 * Enable this component.
21968 * @return {Roo.Component} this
21970 enable : function(){
21974 this.disabled = false;
21975 this.fireEvent("enable", this);
21980 onEnable : function(){
21981 this.getActionEl().removeClass(this.disabledClass);
21982 this.el.dom.disabled = false;
21986 * Convenience function for setting disabled/enabled by boolean.
21987 * @param {Boolean} disabled
21989 setDisabled : function(disabled){
21990 this[disabled ? "disable" : "enable"]();
21994 * Show this component.
21995 * @return {Roo.Component} this
21998 if(this.fireEvent("beforeshow", this) !== false){
21999 this.hidden = false;
22003 this.fireEvent("show", this);
22009 onShow : function(){
22010 var ae = this.getActionEl();
22011 if(this.hideMode == 'visibility'){
22012 ae.dom.style.visibility = "visible";
22013 }else if(this.hideMode == 'offsets'){
22014 ae.removeClass('x-hidden');
22016 ae.dom.style.display = "";
22021 * Hide this component.
22022 * @return {Roo.Component} this
22025 if(this.fireEvent("beforehide", this) !== false){
22026 this.hidden = true;
22030 this.fireEvent("hide", this);
22036 onHide : function(){
22037 var ae = this.getActionEl();
22038 if(this.hideMode == 'visibility'){
22039 ae.dom.style.visibility = "hidden";
22040 }else if(this.hideMode == 'offsets'){
22041 ae.addClass('x-hidden');
22043 ae.dom.style.display = "none";
22048 * Convenience function to hide or show this component by boolean.
22049 * @param {Boolean} visible True to show, false to hide
22050 * @return {Roo.Component} this
22052 setVisible: function(visible){
22062 * Returns true if this component is visible.
22064 isVisible : function(){
22065 return this.getActionEl().isVisible();
22068 cloneConfig : function(overrides){
22069 overrides = overrides || {};
22070 var id = overrides.id || Roo.id();
22071 var cfg = Roo.applyIf(overrides, this.initialConfig);
22072 cfg.id = id; // prevent dup id
22073 return new this.constructor(cfg);
22077 * Ext JS Library 1.1.1
22078 * Copyright(c) 2006-2007, Ext JS, LLC.
22080 * Originally Released Under LGPL - original licence link has changed is not relivant.
22083 * <script type="text/javascript">
22088 * @extends Roo.Element
22089 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22090 * automatic maintaining of shadow/shim positions.
22091 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22092 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22093 * you can pass a string with a CSS class name. False turns off the shadow.
22094 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22095 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22096 * @cfg {String} cls CSS class to add to the element
22097 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22098 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22100 * @param {Object} config An object with config options.
22101 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22104 Roo.Layer = function(config, existingEl){
22105 config = config || {};
22106 var dh = Roo.DomHelper;
22107 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22109 this.dom = Roo.getDom(existingEl);
22112 var o = config.dh || {tag: "div", cls: "x-layer"};
22113 this.dom = dh.append(pel, o);
22116 this.addClass(config.cls);
22118 this.constrain = config.constrain !== false;
22119 this.visibilityMode = Roo.Element.VISIBILITY;
22121 this.id = this.dom.id = config.id;
22123 this.id = Roo.id(this.dom);
22125 this.zindex = config.zindex || this.getZIndex();
22126 this.position("absolute", this.zindex);
22128 this.shadowOffset = config.shadowOffset || 4;
22129 this.shadow = new Roo.Shadow({
22130 offset : this.shadowOffset,
22131 mode : config.shadow
22134 this.shadowOffset = 0;
22136 this.useShim = config.shim !== false && Roo.useShims;
22137 this.useDisplay = config.useDisplay;
22141 var supr = Roo.Element.prototype;
22143 // shims are shared among layer to keep from having 100 iframes
22146 Roo.extend(Roo.Layer, Roo.Element, {
22148 getZIndex : function(){
22149 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22152 getShim : function(){
22159 var shim = shims.shift();
22161 shim = this.createShim();
22162 shim.enableDisplayMode('block');
22163 shim.dom.style.display = 'none';
22164 shim.dom.style.visibility = 'visible';
22166 var pn = this.dom.parentNode;
22167 if(shim.dom.parentNode != pn){
22168 pn.insertBefore(shim.dom, this.dom);
22170 shim.setStyle('z-index', this.getZIndex()-2);
22175 hideShim : function(){
22177 this.shim.setDisplayed(false);
22178 shims.push(this.shim);
22183 disableShadow : function(){
22185 this.shadowDisabled = true;
22186 this.shadow.hide();
22187 this.lastShadowOffset = this.shadowOffset;
22188 this.shadowOffset = 0;
22192 enableShadow : function(show){
22194 this.shadowDisabled = false;
22195 this.shadowOffset = this.lastShadowOffset;
22196 delete this.lastShadowOffset;
22204 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22205 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22206 sync : function(doShow){
22207 var sw = this.shadow;
22208 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22209 var sh = this.getShim();
22211 var w = this.getWidth(),
22212 h = this.getHeight();
22214 var l = this.getLeft(true),
22215 t = this.getTop(true);
22217 if(sw && !this.shadowDisabled){
22218 if(doShow && !sw.isVisible()){
22221 sw.realign(l, t, w, h);
22227 // fit the shim behind the shadow, so it is shimmed too
22228 var a = sw.adjusts, s = sh.dom.style;
22229 s.left = (Math.min(l, l+a.l))+"px";
22230 s.top = (Math.min(t, t+a.t))+"px";
22231 s.width = (w+a.w)+"px";
22232 s.height = (h+a.h)+"px";
22239 sh.setLeftTop(l, t);
22246 destroy : function(){
22249 this.shadow.hide();
22251 this.removeAllListeners();
22252 var pn = this.dom.parentNode;
22254 pn.removeChild(this.dom);
22256 Roo.Element.uncache(this.id);
22259 remove : function(){
22264 beginUpdate : function(){
22265 this.updating = true;
22269 endUpdate : function(){
22270 this.updating = false;
22275 hideUnders : function(negOffset){
22277 this.shadow.hide();
22283 constrainXY : function(){
22284 if(this.constrain){
22285 var vw = Roo.lib.Dom.getViewWidth(),
22286 vh = Roo.lib.Dom.getViewHeight();
22287 var s = Roo.get(document).getScroll();
22289 var xy = this.getXY();
22290 var x = xy[0], y = xy[1];
22291 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22292 // only move it if it needs it
22294 // first validate right/bottom
22295 if((x + w) > vw+s.left){
22296 x = vw - w - this.shadowOffset;
22299 if((y + h) > vh+s.top){
22300 y = vh - h - this.shadowOffset;
22303 // then make sure top/left isn't negative
22314 var ay = this.avoidY;
22315 if(y <= ay && (y+h) >= ay){
22321 supr.setXY.call(this, xy);
22327 isVisible : function(){
22328 return this.visible;
22332 showAction : function(){
22333 this.visible = true; // track visibility to prevent getStyle calls
22334 if(this.useDisplay === true){
22335 this.setDisplayed("");
22336 }else if(this.lastXY){
22337 supr.setXY.call(this, this.lastXY);
22338 }else if(this.lastLT){
22339 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22344 hideAction : function(){
22345 this.visible = false;
22346 if(this.useDisplay === true){
22347 this.setDisplayed(false);
22349 this.setLeftTop(-10000,-10000);
22353 // overridden Element method
22354 setVisible : function(v, a, d, c, e){
22359 var cb = function(){
22364 }.createDelegate(this);
22365 supr.setVisible.call(this, true, true, d, cb, e);
22368 this.hideUnders(true);
22377 }.createDelegate(this);
22379 supr.setVisible.call(this, v, a, d, cb, e);
22388 storeXY : function(xy){
22389 delete this.lastLT;
22393 storeLeftTop : function(left, top){
22394 delete this.lastXY;
22395 this.lastLT = [left, top];
22399 beforeFx : function(){
22400 this.beforeAction();
22401 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22405 afterFx : function(){
22406 Roo.Layer.superclass.afterFx.apply(this, arguments);
22407 this.sync(this.isVisible());
22411 beforeAction : function(){
22412 if(!this.updating && this.shadow){
22413 this.shadow.hide();
22417 // overridden Element method
22418 setLeft : function(left){
22419 this.storeLeftTop(left, this.getTop(true));
22420 supr.setLeft.apply(this, arguments);
22424 setTop : function(top){
22425 this.storeLeftTop(this.getLeft(true), top);
22426 supr.setTop.apply(this, arguments);
22430 setLeftTop : function(left, top){
22431 this.storeLeftTop(left, top);
22432 supr.setLeftTop.apply(this, arguments);
22436 setXY : function(xy, a, d, c, e){
22438 this.beforeAction();
22440 var cb = this.createCB(c);
22441 supr.setXY.call(this, xy, a, d, cb, e);
22448 createCB : function(c){
22459 // overridden Element method
22460 setX : function(x, a, d, c, e){
22461 this.setXY([x, this.getY()], a, d, c, e);
22464 // overridden Element method
22465 setY : function(y, a, d, c, e){
22466 this.setXY([this.getX(), y], a, d, c, e);
22469 // overridden Element method
22470 setSize : function(w, h, a, d, c, e){
22471 this.beforeAction();
22472 var cb = this.createCB(c);
22473 supr.setSize.call(this, w, h, a, d, cb, e);
22479 // overridden Element method
22480 setWidth : function(w, a, d, c, e){
22481 this.beforeAction();
22482 var cb = this.createCB(c);
22483 supr.setWidth.call(this, w, a, d, cb, e);
22489 // overridden Element method
22490 setHeight : function(h, a, d, c, e){
22491 this.beforeAction();
22492 var cb = this.createCB(c);
22493 supr.setHeight.call(this, h, a, d, cb, e);
22499 // overridden Element method
22500 setBounds : function(x, y, w, h, a, d, c, e){
22501 this.beforeAction();
22502 var cb = this.createCB(c);
22504 this.storeXY([x, y]);
22505 supr.setXY.call(this, [x, y]);
22506 supr.setSize.call(this, w, h, a, d, cb, e);
22509 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22515 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22516 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22517 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22518 * @param {Number} zindex The new z-index to set
22519 * @return {this} The Layer
22521 setZIndex : function(zindex){
22522 this.zindex = zindex;
22523 this.setStyle("z-index", zindex + 2);
22525 this.shadow.setZIndex(zindex + 1);
22528 this.shim.setStyle("z-index", zindex);
22534 * Ext JS Library 1.1.1
22535 * Copyright(c) 2006-2007, Ext JS, LLC.
22537 * Originally Released Under LGPL - original licence link has changed is not relivant.
22540 * <script type="text/javascript">
22545 * @class Roo.Shadow
22546 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22547 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22548 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22550 * Create a new Shadow
22551 * @param {Object} config The config object
22553 Roo.Shadow = function(config){
22554 Roo.apply(this, config);
22555 if(typeof this.mode != "string"){
22556 this.mode = this.defaultMode;
22558 var o = this.offset, a = {h: 0};
22559 var rad = Math.floor(this.offset/2);
22560 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22566 a.l -= this.offset + rad;
22567 a.t -= this.offset + rad;
22578 a.l -= (this.offset - rad);
22579 a.t -= this.offset + rad;
22581 a.w -= (this.offset - rad)*2;
22592 a.l -= (this.offset - rad);
22593 a.t -= (this.offset - rad);
22595 a.w -= (this.offset + rad + 1);
22596 a.h -= (this.offset + rad);
22605 Roo.Shadow.prototype = {
22607 * @cfg {String} mode
22608 * The shadow display mode. Supports the following options:<br />
22609 * sides: Shadow displays on both sides and bottom only<br />
22610 * frame: Shadow displays equally on all four sides<br />
22611 * drop: Traditional bottom-right drop shadow (default)
22614 * @cfg {String} offset
22615 * The number of pixels to offset the shadow from the element (defaults to 4)
22620 defaultMode: "drop",
22623 * Displays the shadow under the target element
22624 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22626 show : function(target){
22627 target = Roo.get(target);
22629 this.el = Roo.Shadow.Pool.pull();
22630 if(this.el.dom.nextSibling != target.dom){
22631 this.el.insertBefore(target);
22634 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22636 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22639 target.getLeft(true),
22640 target.getTop(true),
22644 this.el.dom.style.display = "block";
22648 * Returns true if the shadow is visible, else false
22650 isVisible : function(){
22651 return this.el ? true : false;
22655 * Direct alignment when values are already available. Show must be called at least once before
22656 * calling this method to ensure it is initialized.
22657 * @param {Number} left The target element left position
22658 * @param {Number} top The target element top position
22659 * @param {Number} width The target element width
22660 * @param {Number} height The target element height
22662 realign : function(l, t, w, h){
22666 var a = this.adjusts, d = this.el.dom, s = d.style;
22668 s.left = (l+a.l)+"px";
22669 s.top = (t+a.t)+"px";
22670 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22672 if(s.width != sws || s.height != shs){
22676 var cn = d.childNodes;
22677 var sww = Math.max(0, (sw-12))+"px";
22678 cn[0].childNodes[1].style.width = sww;
22679 cn[1].childNodes[1].style.width = sww;
22680 cn[2].childNodes[1].style.width = sww;
22681 cn[1].style.height = Math.max(0, (sh-12))+"px";
22687 * Hides this shadow
22691 this.el.dom.style.display = "none";
22692 Roo.Shadow.Pool.push(this.el);
22698 * Adjust the z-index of this shadow
22699 * @param {Number} zindex The new z-index
22701 setZIndex : function(z){
22704 this.el.setStyle("z-index", z);
22709 // Private utility class that manages the internal Shadow cache
22710 Roo.Shadow.Pool = function(){
22712 var markup = Roo.isIE ?
22713 '<div class="x-ie-shadow"></div>' :
22714 '<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>';
22717 var sh = p.shift();
22719 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22720 sh.autoBoxAdjust = false;
22725 push : function(sh){
22731 * Ext JS Library 1.1.1
22732 * Copyright(c) 2006-2007, Ext JS, LLC.
22734 * Originally Released Under LGPL - original licence link has changed is not relivant.
22737 * <script type="text/javascript">
22741 * @class Roo.BoxComponent
22742 * @extends Roo.Component
22743 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22744 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22745 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22746 * layout containers.
22748 * @param {Roo.Element/String/Object} config The configuration options.
22750 Roo.BoxComponent = function(config){
22751 Roo.Component.call(this, config);
22755 * Fires after the component is resized.
22756 * @param {Roo.Component} this
22757 * @param {Number} adjWidth The box-adjusted width that was set
22758 * @param {Number} adjHeight The box-adjusted height that was set
22759 * @param {Number} rawWidth The width that was originally specified
22760 * @param {Number} rawHeight The height that was originally specified
22765 * Fires after the component is moved.
22766 * @param {Roo.Component} this
22767 * @param {Number} x The new x position
22768 * @param {Number} y The new y position
22774 Roo.extend(Roo.BoxComponent, Roo.Component, {
22775 // private, set in afterRender to signify that the component has been rendered
22777 // private, used to defer height settings to subclasses
22778 deferHeight: false,
22779 /** @cfg {Number} width
22780 * width (optional) size of component
22782 /** @cfg {Number} height
22783 * height (optional) size of component
22787 * Sets the width and height of the component. This method fires the resize event. This method can accept
22788 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22789 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22790 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22791 * @return {Roo.BoxComponent} this
22793 setSize : function(w, h){
22794 // support for standard size objects
22795 if(typeof w == 'object'){
22800 if(!this.boxReady){
22806 // prevent recalcs when not needed
22807 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22810 this.lastSize = {width: w, height: h};
22812 var adj = this.adjustSize(w, h);
22813 var aw = adj.width, ah = adj.height;
22814 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22815 var rz = this.getResizeEl();
22816 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22817 rz.setSize(aw, ah);
22818 }else if(!this.deferHeight && ah !== undefined){
22820 }else if(aw !== undefined){
22823 this.onResize(aw, ah, w, h);
22824 this.fireEvent('resize', this, aw, ah, w, h);
22830 * Gets the current size of the component's underlying element.
22831 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22833 getSize : function(){
22834 return this.el.getSize();
22838 * Gets the current XY position of the component's underlying element.
22839 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22840 * @return {Array} The XY position of the element (e.g., [100, 200])
22842 getPosition : function(local){
22843 if(local === true){
22844 return [this.el.getLeft(true), this.el.getTop(true)];
22846 return this.xy || this.el.getXY();
22850 * Gets the current box measurements of the component's underlying element.
22851 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22852 * @returns {Object} box An object in the format {x, y, width, height}
22854 getBox : function(local){
22855 var s = this.el.getSize();
22857 s.x = this.el.getLeft(true);
22858 s.y = this.el.getTop(true);
22860 var xy = this.xy || this.el.getXY();
22868 * Sets the current box measurements of the component's underlying element.
22869 * @param {Object} box An object in the format {x, y, width, height}
22870 * @returns {Roo.BoxComponent} this
22872 updateBox : function(box){
22873 this.setSize(box.width, box.height);
22874 this.setPagePosition(box.x, box.y);
22879 getResizeEl : function(){
22880 return this.resizeEl || this.el;
22884 getPositionEl : function(){
22885 return this.positionEl || this.el;
22889 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22890 * This method fires the move event.
22891 * @param {Number} left The new left
22892 * @param {Number} top The new top
22893 * @returns {Roo.BoxComponent} this
22895 setPosition : function(x, y){
22898 if(!this.boxReady){
22901 var adj = this.adjustPosition(x, y);
22902 var ax = adj.x, ay = adj.y;
22904 var el = this.getPositionEl();
22905 if(ax !== undefined || ay !== undefined){
22906 if(ax !== undefined && ay !== undefined){
22907 el.setLeftTop(ax, ay);
22908 }else if(ax !== undefined){
22910 }else if(ay !== undefined){
22913 this.onPosition(ax, ay);
22914 this.fireEvent('move', this, ax, ay);
22920 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22921 * This method fires the move event.
22922 * @param {Number} x The new x position
22923 * @param {Number} y The new y position
22924 * @returns {Roo.BoxComponent} this
22926 setPagePosition : function(x, y){
22929 if(!this.boxReady){
22932 if(x === undefined || y === undefined){ // cannot translate undefined points
22935 var p = this.el.translatePoints(x, y);
22936 this.setPosition(p.left, p.top);
22941 onRender : function(ct, position){
22942 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22944 this.resizeEl = Roo.get(this.resizeEl);
22946 if(this.positionEl){
22947 this.positionEl = Roo.get(this.positionEl);
22952 afterRender : function(){
22953 Roo.BoxComponent.superclass.afterRender.call(this);
22954 this.boxReady = true;
22955 this.setSize(this.width, this.height);
22956 if(this.x || this.y){
22957 this.setPosition(this.x, this.y);
22959 if(this.pageX || this.pageY){
22960 this.setPagePosition(this.pageX, this.pageY);
22965 * Force the component's size to recalculate based on the underlying element's current height and width.
22966 * @returns {Roo.BoxComponent} this
22968 syncSize : function(){
22969 delete this.lastSize;
22970 this.setSize(this.el.getWidth(), this.el.getHeight());
22975 * Called after the component is resized, this method is empty by default but can be implemented by any
22976 * subclass that needs to perform custom logic after a resize occurs.
22977 * @param {Number} adjWidth The box-adjusted width that was set
22978 * @param {Number} adjHeight The box-adjusted height that was set
22979 * @param {Number} rawWidth The width that was originally specified
22980 * @param {Number} rawHeight The height that was originally specified
22982 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22987 * Called after the component is moved, this method is empty by default but can be implemented by any
22988 * subclass that needs to perform custom logic after a move occurs.
22989 * @param {Number} x The new x position
22990 * @param {Number} y The new y position
22992 onPosition : function(x, y){
22997 adjustSize : function(w, h){
22998 if(this.autoWidth){
23001 if(this.autoHeight){
23004 return {width : w, height: h};
23008 adjustPosition : function(x, y){
23009 return {x : x, y: y};
23013 * Ext JS Library 1.1.1
23014 * Copyright(c) 2006-2007, Ext JS, LLC.
23016 * Originally Released Under LGPL - original licence link has changed is not relivant.
23019 * <script type="text/javascript">
23024 * @class Roo.SplitBar
23025 * @extends Roo.util.Observable
23026 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23030 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23031 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23032 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23033 split.minSize = 100;
23034 split.maxSize = 600;
23035 split.animate = true;
23036 split.on('moved', splitterMoved);
23039 * Create a new SplitBar
23040 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23041 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23042 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23043 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23044 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23045 position of the SplitBar).
23047 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23050 this.el = Roo.get(dragElement, true);
23051 this.el.dom.unselectable = "on";
23053 this.resizingEl = Roo.get(resizingElement, true);
23057 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23058 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23061 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23064 * The minimum size of the resizing element. (Defaults to 0)
23070 * The maximum size of the resizing element. (Defaults to 2000)
23073 this.maxSize = 2000;
23076 * Whether to animate the transition to the new size
23079 this.animate = false;
23082 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23085 this.useShim = false;
23090 if(!existingProxy){
23092 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23094 this.proxy = Roo.get(existingProxy).dom;
23097 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23100 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23103 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23106 this.dragSpecs = {};
23109 * @private The adapter to use to positon and resize elements
23111 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23112 this.adapter.init(this);
23114 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23116 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23117 this.el.addClass("x-splitbar-h");
23120 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23121 this.el.addClass("x-splitbar-v");
23127 * Fires when the splitter is moved (alias for {@link #event-moved})
23128 * @param {Roo.SplitBar} this
23129 * @param {Number} newSize the new width or height
23134 * Fires when the splitter is moved
23135 * @param {Roo.SplitBar} this
23136 * @param {Number} newSize the new width or height
23140 * @event beforeresize
23141 * Fires before the splitter is dragged
23142 * @param {Roo.SplitBar} this
23144 "beforeresize" : true,
23146 "beforeapply" : true
23149 Roo.util.Observable.call(this);
23152 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23153 onStartProxyDrag : function(x, y){
23154 this.fireEvent("beforeresize", this);
23156 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23158 o.enableDisplayMode("block");
23159 // all splitbars share the same overlay
23160 Roo.SplitBar.prototype.overlay = o;
23162 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23163 this.overlay.show();
23164 Roo.get(this.proxy).setDisplayed("block");
23165 var size = this.adapter.getElementSize(this);
23166 this.activeMinSize = this.getMinimumSize();;
23167 this.activeMaxSize = this.getMaximumSize();;
23168 var c1 = size - this.activeMinSize;
23169 var c2 = Math.max(this.activeMaxSize - size, 0);
23170 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23171 this.dd.resetConstraints();
23172 this.dd.setXConstraint(
23173 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23174 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23176 this.dd.setYConstraint(0, 0);
23178 this.dd.resetConstraints();
23179 this.dd.setXConstraint(0, 0);
23180 this.dd.setYConstraint(
23181 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23182 this.placement == Roo.SplitBar.TOP ? c2 : c1
23185 this.dragSpecs.startSize = size;
23186 this.dragSpecs.startPoint = [x, y];
23187 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23191 * @private Called after the drag operation by the DDProxy
23193 onEndProxyDrag : function(e){
23194 Roo.get(this.proxy).setDisplayed(false);
23195 var endPoint = Roo.lib.Event.getXY(e);
23197 this.overlay.hide();
23200 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23201 newSize = this.dragSpecs.startSize +
23202 (this.placement == Roo.SplitBar.LEFT ?
23203 endPoint[0] - this.dragSpecs.startPoint[0] :
23204 this.dragSpecs.startPoint[0] - endPoint[0]
23207 newSize = this.dragSpecs.startSize +
23208 (this.placement == Roo.SplitBar.TOP ?
23209 endPoint[1] - this.dragSpecs.startPoint[1] :
23210 this.dragSpecs.startPoint[1] - endPoint[1]
23213 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23214 if(newSize != this.dragSpecs.startSize){
23215 if(this.fireEvent('beforeapply', this, newSize) !== false){
23216 this.adapter.setElementSize(this, newSize);
23217 this.fireEvent("moved", this, newSize);
23218 this.fireEvent("resize", this, newSize);
23224 * Get the adapter this SplitBar uses
23225 * @return The adapter object
23227 getAdapter : function(){
23228 return this.adapter;
23232 * Set the adapter this SplitBar uses
23233 * @param {Object} adapter A SplitBar adapter object
23235 setAdapter : function(adapter){
23236 this.adapter = adapter;
23237 this.adapter.init(this);
23241 * Gets the minimum size for the resizing element
23242 * @return {Number} The minimum size
23244 getMinimumSize : function(){
23245 return this.minSize;
23249 * Sets the minimum size for the resizing element
23250 * @param {Number} minSize The minimum size
23252 setMinimumSize : function(minSize){
23253 this.minSize = minSize;
23257 * Gets the maximum size for the resizing element
23258 * @return {Number} The maximum size
23260 getMaximumSize : function(){
23261 return this.maxSize;
23265 * Sets the maximum size for the resizing element
23266 * @param {Number} maxSize The maximum size
23268 setMaximumSize : function(maxSize){
23269 this.maxSize = maxSize;
23273 * Sets the initialize size for the resizing element
23274 * @param {Number} size The initial size
23276 setCurrentSize : function(size){
23277 var oldAnimate = this.animate;
23278 this.animate = false;
23279 this.adapter.setElementSize(this, size);
23280 this.animate = oldAnimate;
23284 * Destroy this splitbar.
23285 * @param {Boolean} removeEl True to remove the element
23287 destroy : function(removeEl){
23289 this.shim.remove();
23292 this.proxy.parentNode.removeChild(this.proxy);
23300 * @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.
23302 Roo.SplitBar.createProxy = function(dir){
23303 var proxy = new Roo.Element(document.createElement("div"));
23304 proxy.unselectable();
23305 var cls = 'x-splitbar-proxy';
23306 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23307 document.body.appendChild(proxy.dom);
23312 * @class Roo.SplitBar.BasicLayoutAdapter
23313 * Default Adapter. It assumes the splitter and resizing element are not positioned
23314 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23316 Roo.SplitBar.BasicLayoutAdapter = function(){
23319 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23320 // do nothing for now
23321 init : function(s){
23325 * Called before drag operations to get the current size of the resizing element.
23326 * @param {Roo.SplitBar} s The SplitBar using this adapter
23328 getElementSize : function(s){
23329 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23330 return s.resizingEl.getWidth();
23332 return s.resizingEl.getHeight();
23337 * Called after drag operations to set the size of the resizing element.
23338 * @param {Roo.SplitBar} s The SplitBar using this adapter
23339 * @param {Number} newSize The new size to set
23340 * @param {Function} onComplete A function to be invoked when resizing is complete
23342 setElementSize : function(s, newSize, onComplete){
23343 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23345 s.resizingEl.setWidth(newSize);
23347 onComplete(s, newSize);
23350 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23355 s.resizingEl.setHeight(newSize);
23357 onComplete(s, newSize);
23360 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23367 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23368 * @extends Roo.SplitBar.BasicLayoutAdapter
23369 * Adapter that moves the splitter element to align with the resized sizing element.
23370 * Used with an absolute positioned SplitBar.
23371 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23372 * document.body, make sure you assign an id to the body element.
23374 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23375 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23376 this.container = Roo.get(container);
23379 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23380 init : function(s){
23381 this.basic.init(s);
23384 getElementSize : function(s){
23385 return this.basic.getElementSize(s);
23388 setElementSize : function(s, newSize, onComplete){
23389 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23392 moveSplitter : function(s){
23393 var yes = Roo.SplitBar;
23394 switch(s.placement){
23396 s.el.setX(s.resizingEl.getRight());
23399 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23402 s.el.setY(s.resizingEl.getBottom());
23405 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23412 * Orientation constant - Create a vertical SplitBar
23416 Roo.SplitBar.VERTICAL = 1;
23419 * Orientation constant - Create a horizontal SplitBar
23423 Roo.SplitBar.HORIZONTAL = 2;
23426 * Placement constant - The resizing element is to the left of the splitter element
23430 Roo.SplitBar.LEFT = 1;
23433 * Placement constant - The resizing element is to the right of the splitter element
23437 Roo.SplitBar.RIGHT = 2;
23440 * Placement constant - The resizing element is positioned above the splitter element
23444 Roo.SplitBar.TOP = 3;
23447 * Placement constant - The resizing element is positioned under splitter element
23451 Roo.SplitBar.BOTTOM = 4;
23454 * Ext JS Library 1.1.1
23455 * Copyright(c) 2006-2007, Ext JS, LLC.
23457 * Originally Released Under LGPL - original licence link has changed is not relivant.
23460 * <script type="text/javascript">
23465 * @extends Roo.util.Observable
23466 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23467 * This class also supports single and multi selection modes. <br>
23468 * Create a data model bound view:
23470 var store = new Roo.data.Store(...);
23472 var view = new Roo.View({
23474 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23476 singleSelect: true,
23477 selectedClass: "ydataview-selected",
23481 // listen for node click?
23482 view.on("click", function(vw, index, node, e){
23483 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23487 dataModel.load("foobar.xml");
23489 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23491 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23492 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23494 * Note: old style constructor is still suported (container, template, config)
23497 * Create a new View
23498 * @param {Object} config The config object
23501 Roo.View = function(config, depreciated_tpl, depreciated_config){
23503 if (typeof(depreciated_tpl) == 'undefined') {
23504 // new way.. - universal constructor.
23505 Roo.apply(this, config);
23506 this.el = Roo.get(this.el);
23509 this.el = Roo.get(config);
23510 this.tpl = depreciated_tpl;
23511 Roo.apply(this, depreciated_config);
23515 if(typeof(this.tpl) == "string"){
23516 this.tpl = new Roo.Template(this.tpl);
23518 // support xtype ctors..
23519 this.tpl = new Roo.factory(this.tpl, Roo);
23523 this.tpl.compile();
23530 * @event beforeclick
23531 * Fires before a click is processed. Returns false to cancel the default action.
23532 * @param {Roo.View} this
23533 * @param {Number} index The index of the target node
23534 * @param {HTMLElement} node The target node
23535 * @param {Roo.EventObject} e The raw event object
23537 "beforeclick" : true,
23540 * Fires when a template node is clicked.
23541 * @param {Roo.View} this
23542 * @param {Number} index The index of the target node
23543 * @param {HTMLElement} node The target node
23544 * @param {Roo.EventObject} e The raw event object
23549 * Fires when a template node is double clicked.
23550 * @param {Roo.View} this
23551 * @param {Number} index The index of the target node
23552 * @param {HTMLElement} node The target node
23553 * @param {Roo.EventObject} e The raw event object
23557 * @event contextmenu
23558 * Fires when a template node is right clicked.
23559 * @param {Roo.View} this
23560 * @param {Number} index The index of the target node
23561 * @param {HTMLElement} node The target node
23562 * @param {Roo.EventObject} e The raw event object
23564 "contextmenu" : true,
23566 * @event selectionchange
23567 * Fires when the selected nodes change.
23568 * @param {Roo.View} this
23569 * @param {Array} selections Array of the selected nodes
23571 "selectionchange" : true,
23574 * @event beforeselect
23575 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23576 * @param {Roo.View} this
23577 * @param {HTMLElement} node The node to be selected
23578 * @param {Array} selections Array of currently selected nodes
23580 "beforeselect" : true
23584 "click": this.onClick,
23585 "dblclick": this.onDblClick,
23586 "contextmenu": this.onContextMenu,
23590 this.selections = [];
23592 this.cmp = new Roo.CompositeElementLite([]);
23594 this.store = Roo.factory(this.store, Roo.data);
23595 this.setStore(this.store, true);
23597 Roo.View.superclass.constructor.call(this);
23600 Roo.extend(Roo.View, Roo.util.Observable, {
23603 * @cfg {Roo.data.Store} store Data store to load data from.
23608 * @cfg {String|Roo.Element} el The container element.
23613 * @cfg {String|Roo.Template} tpl The template used by this View
23618 * @cfg {String} selectedClass The css class to add to selected nodes
23620 selectedClass : "x-view-selected",
23622 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23626 * @cfg {Boolean} multiSelect Allow multiple selection
23629 multiSelect : false,
23631 * @cfg {Boolean} singleSelect Allow single selection
23633 singleSelect: false,
23636 * Returns the element this view is bound to.
23637 * @return {Roo.Element}
23639 getEl : function(){
23644 * Refreshes the view.
23646 refresh : function(){
23648 this.clearSelections();
23649 this.el.update("");
23651 var records = this.store.getRange();
23652 if(records.length < 1){
23653 this.el.update(this.emptyText);
23656 for(var i = 0, len = records.length; i < len; i++){
23657 var data = this.prepareData(records[i].data, i, records[i]);
23658 html[html.length] = t.apply(data);
23660 this.el.update(html.join(""));
23661 this.nodes = this.el.dom.childNodes;
23662 this.updateIndexes(0);
23666 * Function to override to reformat the data that is sent to
23667 * the template for each node.
23668 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23669 * a JSON object for an UpdateManager bound view).
23671 prepareData : function(data){
23675 onUpdate : function(ds, record){
23676 this.clearSelections();
23677 var index = this.store.indexOf(record);
23678 var n = this.nodes[index];
23679 this.tpl.insertBefore(n, this.prepareData(record.data));
23680 n.parentNode.removeChild(n);
23681 this.updateIndexes(index, index);
23684 onAdd : function(ds, records, index){
23685 this.clearSelections();
23686 if(this.nodes.length == 0){
23690 var n = this.nodes[index];
23691 for(var i = 0, len = records.length; i < len; i++){
23692 var d = this.prepareData(records[i].data);
23694 this.tpl.insertBefore(n, d);
23696 this.tpl.append(this.el, d);
23699 this.updateIndexes(index);
23702 onRemove : function(ds, record, index){
23703 this.clearSelections();
23704 this.el.dom.removeChild(this.nodes[index]);
23705 this.updateIndexes(index);
23709 * Refresh an individual node.
23710 * @param {Number} index
23712 refreshNode : function(index){
23713 this.onUpdate(this.store, this.store.getAt(index));
23716 updateIndexes : function(startIndex, endIndex){
23717 var ns = this.nodes;
23718 startIndex = startIndex || 0;
23719 endIndex = endIndex || ns.length - 1;
23720 for(var i = startIndex; i <= endIndex; i++){
23721 ns[i].nodeIndex = i;
23726 * Changes the data store this view uses and refresh the view.
23727 * @param {Store} store
23729 setStore : function(store, initial){
23730 if(!initial && this.store){
23731 this.store.un("datachanged", this.refresh);
23732 this.store.un("add", this.onAdd);
23733 this.store.un("remove", this.onRemove);
23734 this.store.un("update", this.onUpdate);
23735 this.store.un("clear", this.refresh);
23739 store.on("datachanged", this.refresh, this);
23740 store.on("add", this.onAdd, this);
23741 store.on("remove", this.onRemove, this);
23742 store.on("update", this.onUpdate, this);
23743 store.on("clear", this.refresh, this);
23752 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23753 * @param {HTMLElement} node
23754 * @return {HTMLElement} The template node
23756 findItemFromChild : function(node){
23757 var el = this.el.dom;
23758 if(!node || node.parentNode == el){
23761 var p = node.parentNode;
23762 while(p && p != el){
23763 if(p.parentNode == el){
23772 onClick : function(e){
23773 var item = this.findItemFromChild(e.getTarget());
23775 var index = this.indexOf(item);
23776 if(this.onItemClick(item, index, e) !== false){
23777 this.fireEvent("click", this, index, item, e);
23780 this.clearSelections();
23785 onContextMenu : function(e){
23786 var item = this.findItemFromChild(e.getTarget());
23788 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23793 onDblClick : function(e){
23794 var item = this.findItemFromChild(e.getTarget());
23796 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23800 onItemClick : function(item, index, e){
23801 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23804 if(this.multiSelect || this.singleSelect){
23805 if(this.multiSelect && e.shiftKey && this.lastSelection){
23806 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23808 this.select(item, this.multiSelect && e.ctrlKey);
23809 this.lastSelection = item;
23811 e.preventDefault();
23817 * Get the number of selected nodes.
23820 getSelectionCount : function(){
23821 return this.selections.length;
23825 * Get the currently selected nodes.
23826 * @return {Array} An array of HTMLElements
23828 getSelectedNodes : function(){
23829 return this.selections;
23833 * Get the indexes of the selected nodes.
23836 getSelectedIndexes : function(){
23837 var indexes = [], s = this.selections;
23838 for(var i = 0, len = s.length; i < len; i++){
23839 indexes.push(s[i].nodeIndex);
23845 * Clear all selections
23846 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23848 clearSelections : function(suppressEvent){
23849 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23850 this.cmp.elements = this.selections;
23851 this.cmp.removeClass(this.selectedClass);
23852 this.selections = [];
23853 if(!suppressEvent){
23854 this.fireEvent("selectionchange", this, this.selections);
23860 * Returns true if the passed node is selected
23861 * @param {HTMLElement/Number} node The node or node index
23862 * @return {Boolean}
23864 isSelected : function(node){
23865 var s = this.selections;
23869 node = this.getNode(node);
23870 return s.indexOf(node) !== -1;
23875 * @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
23876 * @param {Boolean} keepExisting (optional) true to keep existing selections
23877 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23879 select : function(nodeInfo, keepExisting, suppressEvent){
23880 if(nodeInfo instanceof Array){
23882 this.clearSelections(true);
23884 for(var i = 0, len = nodeInfo.length; i < len; i++){
23885 this.select(nodeInfo[i], true, true);
23888 var node = this.getNode(nodeInfo);
23889 if(node && !this.isSelected(node)){
23891 this.clearSelections(true);
23893 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23894 Roo.fly(node).addClass(this.selectedClass);
23895 this.selections.push(node);
23896 if(!suppressEvent){
23897 this.fireEvent("selectionchange", this, this.selections);
23905 * Gets a template node.
23906 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23907 * @return {HTMLElement} The node or null if it wasn't found
23909 getNode : function(nodeInfo){
23910 if(typeof nodeInfo == "string"){
23911 return document.getElementById(nodeInfo);
23912 }else if(typeof nodeInfo == "number"){
23913 return this.nodes[nodeInfo];
23919 * Gets a range template nodes.
23920 * @param {Number} startIndex
23921 * @param {Number} endIndex
23922 * @return {Array} An array of nodes
23924 getNodes : function(start, end){
23925 var ns = this.nodes;
23926 start = start || 0;
23927 end = typeof end == "undefined" ? ns.length - 1 : end;
23930 for(var i = start; i <= end; i++){
23934 for(var i = start; i >= end; i--){
23942 * Finds the index of the passed node
23943 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23944 * @return {Number} The index of the node or -1
23946 indexOf : function(node){
23947 node = this.getNode(node);
23948 if(typeof node.nodeIndex == "number"){
23949 return node.nodeIndex;
23951 var ns = this.nodes;
23952 for(var i = 0, len = ns.length; i < len; i++){
23962 * Ext JS Library 1.1.1
23963 * Copyright(c) 2006-2007, Ext JS, LLC.
23965 * Originally Released Under LGPL - original licence link has changed is not relivant.
23968 * <script type="text/javascript">
23972 * @class Roo.JsonView
23973 * @extends Roo.View
23974 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23976 var view = new Roo.JsonView({
23977 container: "my-element",
23978 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
23983 // listen for node click?
23984 view.on("click", function(vw, index, node, e){
23985 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23988 // direct load of JSON data
23989 view.load("foobar.php");
23991 // Example from my blog list
23992 var tpl = new Roo.Template(
23993 '<div class="entry">' +
23994 '<a class="entry-title" href="{link}">{title}</a>' +
23995 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23996 "</div><hr />"
23999 var moreView = new Roo.JsonView({
24000 container : "entry-list",
24004 moreView.on("beforerender", this.sortEntries, this);
24006 url: "/blog/get-posts.php",
24007 params: "allposts=true",
24008 text: "Loading Blog Entries..."
24012 * Note: old code is supported with arguments : (container, template, config)
24016 * Create a new JsonView
24018 * @param {Object} config The config object
24021 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24024 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24026 var um = this.el.getUpdateManager();
24027 um.setRenderer(this);
24028 um.on("update", this.onLoad, this);
24029 um.on("failure", this.onLoadException, this);
24032 * @event beforerender
24033 * Fires before rendering of the downloaded JSON data.
24034 * @param {Roo.JsonView} this
24035 * @param {Object} data The JSON data loaded
24039 * Fires when data is loaded.
24040 * @param {Roo.JsonView} this
24041 * @param {Object} data The JSON data loaded
24042 * @param {Object} response The raw Connect response object
24045 * @event loadexception
24046 * Fires when loading fails.
24047 * @param {Roo.JsonView} this
24048 * @param {Object} response The raw Connect response object
24051 'beforerender' : true,
24053 'loadexception' : true
24056 Roo.extend(Roo.JsonView, Roo.View, {
24058 * @type {String} The root property in the loaded JSON object that contains the data
24063 * Refreshes the view.
24065 refresh : function(){
24066 this.clearSelections();
24067 this.el.update("");
24069 var o = this.jsonData;
24070 if(o && o.length > 0){
24071 for(var i = 0, len = o.length; i < len; i++){
24072 var data = this.prepareData(o[i], i, o);
24073 html[html.length] = this.tpl.apply(data);
24076 html.push(this.emptyText);
24078 this.el.update(html.join(""));
24079 this.nodes = this.el.dom.childNodes;
24080 this.updateIndexes(0);
24084 * 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.
24085 * @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:
24088 url: "your-url.php",
24089 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24090 callback: yourFunction,
24091 scope: yourObject, //(optional scope)
24094 text: "Loading...",
24099 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24100 * 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.
24101 * @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}
24102 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24103 * @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.
24106 var um = this.el.getUpdateManager();
24107 um.update.apply(um, arguments);
24110 render : function(el, response){
24111 this.clearSelections();
24112 this.el.update("");
24115 o = Roo.util.JSON.decode(response.responseText);
24118 o = o[this.jsonRoot];
24123 * The current JSON data or null
24126 this.beforeRender();
24131 * Get the number of records in the current JSON dataset
24134 getCount : function(){
24135 return this.jsonData ? this.jsonData.length : 0;
24139 * Returns the JSON object for the specified node(s)
24140 * @param {HTMLElement/Array} node The node or an array of nodes
24141 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24142 * you get the JSON object for the node
24144 getNodeData : function(node){
24145 if(node instanceof Array){
24147 for(var i = 0, len = node.length; i < len; i++){
24148 data.push(this.getNodeData(node[i]));
24152 return this.jsonData[this.indexOf(node)] || null;
24155 beforeRender : function(){
24156 this.snapshot = this.jsonData;
24158 this.sort.apply(this, this.sortInfo);
24160 this.fireEvent("beforerender", this, this.jsonData);
24163 onLoad : function(el, o){
24164 this.fireEvent("load", this, this.jsonData, o);
24167 onLoadException : function(el, o){
24168 this.fireEvent("loadexception", this, o);
24172 * Filter the data by a specific property.
24173 * @param {String} property A property on your JSON objects
24174 * @param {String/RegExp} value Either string that the property values
24175 * should start with, or a RegExp to test against the property
24177 filter : function(property, value){
24180 var ss = this.snapshot;
24181 if(typeof value == "string"){
24182 var vlen = value.length;
24184 this.clearFilter();
24187 value = value.toLowerCase();
24188 for(var i = 0, len = ss.length; i < len; i++){
24190 if(o[property].substr(0, vlen).toLowerCase() == value){
24194 } else if(value.exec){ // regex?
24195 for(var i = 0, len = ss.length; i < len; i++){
24197 if(value.test(o[property])){
24204 this.jsonData = data;
24210 * Filter by a function. The passed function will be called with each
24211 * object in the current dataset. If the function returns true the value is kept,
24212 * otherwise it is filtered.
24213 * @param {Function} fn
24214 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24216 filterBy : function(fn, scope){
24219 var ss = this.snapshot;
24220 for(var i = 0, len = ss.length; i < len; i++){
24222 if(fn.call(scope || this, o)){
24226 this.jsonData = data;
24232 * Clears the current filter.
24234 clearFilter : function(){
24235 if(this.snapshot && this.jsonData != this.snapshot){
24236 this.jsonData = this.snapshot;
24243 * Sorts the data for this view and refreshes it.
24244 * @param {String} property A property on your JSON objects to sort on
24245 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24246 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24248 sort : function(property, dir, sortType){
24249 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24252 var dsc = dir && dir.toLowerCase() == "desc";
24253 var f = function(o1, o2){
24254 var v1 = sortType ? sortType(o1[p]) : o1[p];
24255 var v2 = sortType ? sortType(o2[p]) : o2[p];
24258 return dsc ? +1 : -1;
24259 } else if(v1 > v2){
24260 return dsc ? -1 : +1;
24265 this.jsonData.sort(f);
24267 if(this.jsonData != this.snapshot){
24268 this.snapshot.sort(f);
24274 * Ext JS Library 1.1.1
24275 * Copyright(c) 2006-2007, Ext JS, LLC.
24277 * Originally Released Under LGPL - original licence link has changed is not relivant.
24280 * <script type="text/javascript">
24285 * @class Roo.ColorPalette
24286 * @extends Roo.Component
24287 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24288 * Here's an example of typical usage:
24290 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24291 cp.render('my-div');
24293 cp.on('select', function(palette, selColor){
24294 // do something with selColor
24298 * Create a new ColorPalette
24299 * @param {Object} config The config object
24301 Roo.ColorPalette = function(config){
24302 Roo.ColorPalette.superclass.constructor.call(this, config);
24306 * Fires when a color is selected
24307 * @param {ColorPalette} this
24308 * @param {String} color The 6-digit color hex code (without the # symbol)
24314 this.on("select", this.handler, this.scope, true);
24317 Roo.extend(Roo.ColorPalette, Roo.Component, {
24319 * @cfg {String} itemCls
24320 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24322 itemCls : "x-color-palette",
24324 * @cfg {String} value
24325 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24326 * the hex codes are case-sensitive.
24329 clickEvent:'click',
24331 ctype: "Roo.ColorPalette",
24334 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24336 allowReselect : false,
24339 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24340 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24341 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24342 * of colors with the width setting until the box is symmetrical.</p>
24343 * <p>You can override individual colors if needed:</p>
24345 var cp = new Roo.ColorPalette();
24346 cp.colors[0] = "FF0000"; // change the first box to red
24349 Or you can provide a custom array of your own for complete control:
24351 var cp = new Roo.ColorPalette();
24352 cp.colors = ["000000", "993300", "333300"];
24357 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24358 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24359 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24360 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24361 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24365 onRender : function(container, position){
24366 var t = new Roo.MasterTemplate(
24367 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24369 var c = this.colors;
24370 for(var i = 0, len = c.length; i < len; i++){
24373 var el = document.createElement("div");
24374 el.className = this.itemCls;
24376 container.dom.insertBefore(el, position);
24377 this.el = Roo.get(el);
24378 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24379 if(this.clickEvent != 'click'){
24380 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24385 afterRender : function(){
24386 Roo.ColorPalette.superclass.afterRender.call(this);
24388 var s = this.value;
24395 handleClick : function(e, t){
24396 e.preventDefault();
24397 if(!this.disabled){
24398 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24399 this.select(c.toUpperCase());
24404 * Selects the specified color in the palette (fires the select event)
24405 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24407 select : function(color){
24408 color = color.replace("#", "");
24409 if(color != this.value || this.allowReselect){
24412 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24414 el.child("a.color-"+color).addClass("x-color-palette-sel");
24415 this.value = color;
24416 this.fireEvent("select", this, color);
24421 * Ext JS Library 1.1.1
24422 * Copyright(c) 2006-2007, Ext JS, LLC.
24424 * Originally Released Under LGPL - original licence link has changed is not relivant.
24427 * <script type="text/javascript">
24431 * @class Roo.DatePicker
24432 * @extends Roo.Component
24433 * Simple date picker class.
24435 * Create a new DatePicker
24436 * @param {Object} config The config object
24438 Roo.DatePicker = function(config){
24439 Roo.DatePicker.superclass.constructor.call(this, config);
24441 this.value = config && config.value ?
24442 config.value.clearTime() : new Date().clearTime();
24447 * Fires when a date is selected
24448 * @param {DatePicker} this
24449 * @param {Date} date The selected date
24455 this.on("select", this.handler, this.scope || this);
24457 // build the disabledDatesRE
24458 if(!this.disabledDatesRE && this.disabledDates){
24459 var dd = this.disabledDates;
24461 for(var i = 0; i < dd.length; i++){
24463 if(i != dd.length-1) re += "|";
24465 this.disabledDatesRE = new RegExp(re + ")");
24469 Roo.extend(Roo.DatePicker, Roo.Component, {
24471 * @cfg {String} todayText
24472 * The text to display on the button that selects the current date (defaults to "Today")
24474 todayText : "Today",
24476 * @cfg {String} okText
24477 * The text to display on the ok button
24479 okText : " OK ", //   to give the user extra clicking room
24481 * @cfg {String} cancelText
24482 * The text to display on the cancel button
24484 cancelText : "Cancel",
24486 * @cfg {String} todayTip
24487 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24489 todayTip : "{0} (Spacebar)",
24491 * @cfg {Date} minDate
24492 * Minimum allowable date (JavaScript date object, defaults to null)
24496 * @cfg {Date} maxDate
24497 * Maximum allowable date (JavaScript date object, defaults to null)
24501 * @cfg {String} minText
24502 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24504 minText : "This date is before the minimum date",
24506 * @cfg {String} maxText
24507 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24509 maxText : "This date is after the maximum date",
24511 * @cfg {String} format
24512 * The default date format string which can be overriden for localization support. The format must be
24513 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24517 * @cfg {Array} disabledDays
24518 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24520 disabledDays : null,
24522 * @cfg {String} disabledDaysText
24523 * The tooltip to display when the date falls on a disabled day (defaults to "")
24525 disabledDaysText : "",
24527 * @cfg {RegExp} disabledDatesRE
24528 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24530 disabledDatesRE : null,
24532 * @cfg {String} disabledDatesText
24533 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24535 disabledDatesText : "",
24537 * @cfg {Boolean} constrainToViewport
24538 * True to constrain the date picker to the viewport (defaults to true)
24540 constrainToViewport : true,
24542 * @cfg {Array} monthNames
24543 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24545 monthNames : Date.monthNames,
24547 * @cfg {Array} dayNames
24548 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24550 dayNames : Date.dayNames,
24552 * @cfg {String} nextText
24553 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24555 nextText: 'Next Month (Control+Right)',
24557 * @cfg {String} prevText
24558 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24560 prevText: 'Previous Month (Control+Left)',
24562 * @cfg {String} monthYearText
24563 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24565 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24567 * @cfg {Number} startDay
24568 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24572 * @cfg {Bool} showClear
24573 * Show a clear button (usefull for date form elements that can be blank.)
24579 * Sets the value of the date field
24580 * @param {Date} value The date to set
24582 setValue : function(value){
24583 var old = this.value;
24584 this.value = value.clearTime(true);
24586 this.update(this.value);
24591 * Gets the current selected value of the date field
24592 * @return {Date} The selected date
24594 getValue : function(){
24599 focus : function(){
24601 this.update(this.activeDate);
24606 onRender : function(container, position){
24608 '<table cellspacing="0">',
24609 '<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>',
24610 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24611 var dn = this.dayNames;
24612 for(var i = 0; i < 7; i++){
24613 var d = this.startDay+i;
24617 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24619 m[m.length] = "</tr></thead><tbody><tr>";
24620 for(var i = 0; i < 42; i++) {
24621 if(i % 7 == 0 && i != 0){
24622 m[m.length] = "</tr><tr>";
24624 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24626 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24627 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24629 var el = document.createElement("div");
24630 el.className = "x-date-picker";
24631 el.innerHTML = m.join("");
24633 container.dom.insertBefore(el, position);
24635 this.el = Roo.get(el);
24636 this.eventEl = Roo.get(el.firstChild);
24638 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24639 handler: this.showPrevMonth,
24641 preventDefault:true,
24645 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24646 handler: this.showNextMonth,
24648 preventDefault:true,
24652 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24654 this.monthPicker = this.el.down('div.x-date-mp');
24655 this.monthPicker.enableDisplayMode('block');
24657 var kn = new Roo.KeyNav(this.eventEl, {
24658 "left" : function(e){
24660 this.showPrevMonth() :
24661 this.update(this.activeDate.add("d", -1));
24664 "right" : function(e){
24666 this.showNextMonth() :
24667 this.update(this.activeDate.add("d", 1));
24670 "up" : function(e){
24672 this.showNextYear() :
24673 this.update(this.activeDate.add("d", -7));
24676 "down" : function(e){
24678 this.showPrevYear() :
24679 this.update(this.activeDate.add("d", 7));
24682 "pageUp" : function(e){
24683 this.showNextMonth();
24686 "pageDown" : function(e){
24687 this.showPrevMonth();
24690 "enter" : function(e){
24691 e.stopPropagation();
24698 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24700 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24702 this.el.unselectable();
24704 this.cells = this.el.select("table.x-date-inner tbody td");
24705 this.textNodes = this.el.query("table.x-date-inner tbody span");
24707 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24709 tooltip: this.monthYearText
24712 this.mbtn.on('click', this.showMonthPicker, this);
24713 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24716 var today = (new Date()).dateFormat(this.format);
24718 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24719 if (this.showClear) {
24720 baseTb.add( new Roo.Toolbar.Fill());
24723 text: String.format(this.todayText, today),
24724 tooltip: String.format(this.todayTip, today),
24725 handler: this.selectToday,
24729 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24732 if (this.showClear) {
24734 baseTb.add( new Roo.Toolbar.Fill());
24737 cls: 'x-btn-icon x-btn-clear',
24738 handler: function() {
24740 this.fireEvent("select", this, '');
24750 this.update(this.value);
24753 createMonthPicker : function(){
24754 if(!this.monthPicker.dom.firstChild){
24755 var buf = ['<table border="0" cellspacing="0">'];
24756 for(var i = 0; i < 6; i++){
24758 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24759 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24761 '<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>' :
24762 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24766 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24768 '</button><button type="button" class="x-date-mp-cancel">',
24770 '</button></td></tr>',
24773 this.monthPicker.update(buf.join(''));
24774 this.monthPicker.on('click', this.onMonthClick, this);
24775 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24777 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24778 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24780 this.mpMonths.each(function(m, a, i){
24783 m.dom.xmonth = 5 + Math.round(i * .5);
24785 m.dom.xmonth = Math.round((i-1) * .5);
24791 showMonthPicker : function(){
24792 this.createMonthPicker();
24793 var size = this.el.getSize();
24794 this.monthPicker.setSize(size);
24795 this.monthPicker.child('table').setSize(size);
24797 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24798 this.updateMPMonth(this.mpSelMonth);
24799 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24800 this.updateMPYear(this.mpSelYear);
24802 this.monthPicker.slideIn('t', {duration:.2});
24805 updateMPYear : function(y){
24807 var ys = this.mpYears.elements;
24808 for(var i = 1; i <= 10; i++){
24809 var td = ys[i-1], y2;
24811 y2 = y + Math.round(i * .5);
24812 td.firstChild.innerHTML = y2;
24815 y2 = y - (5-Math.round(i * .5));
24816 td.firstChild.innerHTML = y2;
24819 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24823 updateMPMonth : function(sm){
24824 this.mpMonths.each(function(m, a, i){
24825 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24829 selectMPMonth: function(m){
24833 onMonthClick : function(e, t){
24835 var el = new Roo.Element(t), pn;
24836 if(el.is('button.x-date-mp-cancel')){
24837 this.hideMonthPicker();
24839 else if(el.is('button.x-date-mp-ok')){
24840 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24841 this.hideMonthPicker();
24843 else if(pn = el.up('td.x-date-mp-month', 2)){
24844 this.mpMonths.removeClass('x-date-mp-sel');
24845 pn.addClass('x-date-mp-sel');
24846 this.mpSelMonth = pn.dom.xmonth;
24848 else if(pn = el.up('td.x-date-mp-year', 2)){
24849 this.mpYears.removeClass('x-date-mp-sel');
24850 pn.addClass('x-date-mp-sel');
24851 this.mpSelYear = pn.dom.xyear;
24853 else if(el.is('a.x-date-mp-prev')){
24854 this.updateMPYear(this.mpyear-10);
24856 else if(el.is('a.x-date-mp-next')){
24857 this.updateMPYear(this.mpyear+10);
24861 onMonthDblClick : function(e, t){
24863 var el = new Roo.Element(t), pn;
24864 if(pn = el.up('td.x-date-mp-month', 2)){
24865 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24866 this.hideMonthPicker();
24868 else if(pn = el.up('td.x-date-mp-year', 2)){
24869 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24870 this.hideMonthPicker();
24874 hideMonthPicker : function(disableAnim){
24875 if(this.monthPicker){
24876 if(disableAnim === true){
24877 this.monthPicker.hide();
24879 this.monthPicker.slideOut('t', {duration:.2});
24885 showPrevMonth : function(e){
24886 this.update(this.activeDate.add("mo", -1));
24890 showNextMonth : function(e){
24891 this.update(this.activeDate.add("mo", 1));
24895 showPrevYear : function(){
24896 this.update(this.activeDate.add("y", -1));
24900 showNextYear : function(){
24901 this.update(this.activeDate.add("y", 1));
24905 handleMouseWheel : function(e){
24906 var delta = e.getWheelDelta();
24908 this.showPrevMonth();
24910 } else if(delta < 0){
24911 this.showNextMonth();
24917 handleDateClick : function(e, t){
24919 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24920 this.setValue(new Date(t.dateValue));
24921 this.fireEvent("select", this, this.value);
24926 selectToday : function(){
24927 this.setValue(new Date().clearTime());
24928 this.fireEvent("select", this, this.value);
24932 update : function(date){
24933 var vd = this.activeDate;
24934 this.activeDate = date;
24936 var t = date.getTime();
24937 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24938 this.cells.removeClass("x-date-selected");
24939 this.cells.each(function(c){
24940 if(c.dom.firstChild.dateValue == t){
24941 c.addClass("x-date-selected");
24942 setTimeout(function(){
24943 try{c.dom.firstChild.focus();}catch(e){}
24951 var days = date.getDaysInMonth();
24952 var firstOfMonth = date.getFirstDateOfMonth();
24953 var startingPos = firstOfMonth.getDay()-this.startDay;
24955 if(startingPos <= this.startDay){
24959 var pm = date.add("mo", -1);
24960 var prevStart = pm.getDaysInMonth()-startingPos;
24962 var cells = this.cells.elements;
24963 var textEls = this.textNodes;
24964 days += startingPos;
24966 // convert everything to numbers so it's fast
24967 var day = 86400000;
24968 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24969 var today = new Date().clearTime().getTime();
24970 var sel = date.clearTime().getTime();
24971 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24972 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24973 var ddMatch = this.disabledDatesRE;
24974 var ddText = this.disabledDatesText;
24975 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24976 var ddaysText = this.disabledDaysText;
24977 var format = this.format;
24979 var setCellClass = function(cal, cell){
24981 var t = d.getTime();
24982 cell.firstChild.dateValue = t;
24984 cell.className += " x-date-today";
24985 cell.title = cal.todayText;
24988 cell.className += " x-date-selected";
24989 setTimeout(function(){
24990 try{cell.firstChild.focus();}catch(e){}
24995 cell.className = " x-date-disabled";
24996 cell.title = cal.minText;
25000 cell.className = " x-date-disabled";
25001 cell.title = cal.maxText;
25005 if(ddays.indexOf(d.getDay()) != -1){
25006 cell.title = ddaysText;
25007 cell.className = " x-date-disabled";
25010 if(ddMatch && format){
25011 var fvalue = d.dateFormat(format);
25012 if(ddMatch.test(fvalue)){
25013 cell.title = ddText.replace("%0", fvalue);
25014 cell.className = " x-date-disabled";
25020 for(; i < startingPos; i++) {
25021 textEls[i].innerHTML = (++prevStart);
25022 d.setDate(d.getDate()+1);
25023 cells[i].className = "x-date-prevday";
25024 setCellClass(this, cells[i]);
25026 for(; i < days; i++){
25027 intDay = i - startingPos + 1;
25028 textEls[i].innerHTML = (intDay);
25029 d.setDate(d.getDate()+1);
25030 cells[i].className = "x-date-active";
25031 setCellClass(this, cells[i]);
25034 for(; i < 42; i++) {
25035 textEls[i].innerHTML = (++extraDays);
25036 d.setDate(d.getDate()+1);
25037 cells[i].className = "x-date-nextday";
25038 setCellClass(this, cells[i]);
25041 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25043 if(!this.internalRender){
25044 var main = this.el.dom.firstChild;
25045 var w = main.offsetWidth;
25046 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25047 Roo.fly(main).setWidth(w);
25048 this.internalRender = true;
25049 // opera does not respect the auto grow header center column
25050 // then, after it gets a width opera refuses to recalculate
25051 // without a second pass
25052 if(Roo.isOpera && !this.secondPass){
25053 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25054 this.secondPass = true;
25055 this.update.defer(10, this, [date]);
25061 * Ext JS Library 1.1.1
25062 * Copyright(c) 2006-2007, Ext JS, LLC.
25064 * Originally Released Under LGPL - original licence link has changed is not relivant.
25067 * <script type="text/javascript">
25070 * @class Roo.TabPanel
25071 * @extends Roo.util.Observable
25072 * A lightweight tab container.
25076 // basic tabs 1, built from existing content
25077 var tabs = new Roo.TabPanel("tabs1");
25078 tabs.addTab("script", "View Script");
25079 tabs.addTab("markup", "View Markup");
25080 tabs.activate("script");
25082 // more advanced tabs, built from javascript
25083 var jtabs = new Roo.TabPanel("jtabs");
25084 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25086 // set up the UpdateManager
25087 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25088 var updater = tab2.getUpdateManager();
25089 updater.setDefaultUrl("ajax1.htm");
25090 tab2.on('activate', updater.refresh, updater, true);
25092 // Use setUrl for Ajax loading
25093 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25094 tab3.setUrl("ajax2.htm", null, true);
25097 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25100 jtabs.activate("jtabs-1");
25103 * Create a new TabPanel.
25104 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25105 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25107 Roo.TabPanel = function(container, config){
25109 * The container element for this TabPanel.
25110 * @type Roo.Element
25112 this.el = Roo.get(container, true);
25114 if(typeof config == "boolean"){
25115 this.tabPosition = config ? "bottom" : "top";
25117 Roo.apply(this, config);
25120 if(this.tabPosition == "bottom"){
25121 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25122 this.el.addClass("x-tabs-bottom");
25124 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25125 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25126 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25128 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25130 if(this.tabPosition != "bottom"){
25131 /** The body element that contains {@link Roo.TabPanelItem} bodies.
25132 * @type Roo.Element
25134 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25135 this.el.addClass("x-tabs-top");
25139 this.bodyEl.setStyle("position", "relative");
25141 this.active = null;
25142 this.activateDelegate = this.activate.createDelegate(this);
25147 * Fires when the active tab changes
25148 * @param {Roo.TabPanel} this
25149 * @param {Roo.TabPanelItem} activePanel The new active tab
25153 * @event beforetabchange
25154 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25155 * @param {Roo.TabPanel} this
25156 * @param {Object} e Set cancel to true on this object to cancel the tab change
25157 * @param {Roo.TabPanelItem} tab The tab being changed to
25159 "beforetabchange" : true
25162 Roo.EventManager.onWindowResize(this.onResize, this);
25163 this.cpad = this.el.getPadding("lr");
25164 this.hiddenCount = 0;
25166 Roo.TabPanel.superclass.constructor.call(this);
25169 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25171 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25173 tabPosition : "top",
25175 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25177 currentTabWidth : 0,
25179 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25183 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25187 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25189 preferredTabWidth : 175,
25191 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25193 resizeTabs : false,
25195 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25197 monitorResize : true,
25200 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25201 * @param {String} id The id of the div to use <b>or create</b>
25202 * @param {String} text The text for the tab
25203 * @param {String} content (optional) Content to put in the TabPanelItem body
25204 * @param {Boolean} closable (optional) True to create a close icon on the tab
25205 * @return {Roo.TabPanelItem} The created TabPanelItem
25207 addTab : function(id, text, content, closable){
25208 var item = new Roo.TabPanelItem(this, id, text, closable);
25209 this.addTabItem(item);
25211 item.setContent(content);
25217 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25218 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25219 * @return {Roo.TabPanelItem}
25221 getTab : function(id){
25222 return this.items[id];
25226 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25227 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25229 hideTab : function(id){
25230 var t = this.items[id];
25233 this.hiddenCount++;
25234 this.autoSizeTabs();
25239 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25240 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25242 unhideTab : function(id){
25243 var t = this.items[id];
25245 t.setHidden(false);
25246 this.hiddenCount--;
25247 this.autoSizeTabs();
25252 * Adds an existing {@link Roo.TabPanelItem}.
25253 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25255 addTabItem : function(item){
25256 this.items[item.id] = item;
25257 this.items.push(item);
25258 if(this.resizeTabs){
25259 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25260 this.autoSizeTabs();
25267 * Removes a {@link Roo.TabPanelItem}.
25268 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25270 removeTab : function(id){
25271 var items = this.items;
25272 var tab = items[id];
25273 if(!tab) { return; }
25274 var index = items.indexOf(tab);
25275 if(this.active == tab && items.length > 1){
25276 var newTab = this.getNextAvailable(index);
25281 this.stripEl.dom.removeChild(tab.pnode.dom);
25282 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25283 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25285 items.splice(index, 1);
25286 delete this.items[tab.id];
25287 tab.fireEvent("close", tab);
25288 tab.purgeListeners();
25289 this.autoSizeTabs();
25292 getNextAvailable : function(start){
25293 var items = this.items;
25295 // look for a next tab that will slide over to
25296 // replace the one being removed
25297 while(index < items.length){
25298 var item = items[++index];
25299 if(item && !item.isHidden()){
25303 // if one isn't found select the previous tab (on the left)
25306 var item = items[--index];
25307 if(item && !item.isHidden()){
25315 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25316 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25318 disableTab : function(id){
25319 var tab = this.items[id];
25320 if(tab && this.active != tab){
25326 * Enables a {@link Roo.TabPanelItem} that is disabled.
25327 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25329 enableTab : function(id){
25330 var tab = this.items[id];
25335 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25336 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25337 * @return {Roo.TabPanelItem} The TabPanelItem.
25339 activate : function(id){
25340 var tab = this.items[id];
25344 if(tab == this.active || tab.disabled){
25348 this.fireEvent("beforetabchange", this, e, tab);
25349 if(e.cancel !== true && !tab.disabled){
25351 this.active.hide();
25353 this.active = this.items[id];
25354 this.active.show();
25355 this.fireEvent("tabchange", this, this.active);
25361 * Gets the active {@link Roo.TabPanelItem}.
25362 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25364 getActiveTab : function(){
25365 return this.active;
25369 * Updates the tab body element to fit the height of the container element
25370 * for overflow scrolling
25371 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25373 syncHeight : function(targetHeight){
25374 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25375 var bm = this.bodyEl.getMargins();
25376 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25377 this.bodyEl.setHeight(newHeight);
25381 onResize : function(){
25382 if(this.monitorResize){
25383 this.autoSizeTabs();
25388 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25390 beginUpdate : function(){
25391 this.updating = true;
25395 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25397 endUpdate : function(){
25398 this.updating = false;
25399 this.autoSizeTabs();
25403 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25405 autoSizeTabs : function(){
25406 var count = this.items.length;
25407 var vcount = count - this.hiddenCount;
25408 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25409 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25410 var availWidth = Math.floor(w / vcount);
25411 var b = this.stripBody;
25412 if(b.getWidth() > w){
25413 var tabs = this.items;
25414 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25415 if(availWidth < this.minTabWidth){
25416 /*if(!this.sleft){ // incomplete scrolling code
25417 this.createScrollButtons();
25420 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25423 if(this.currentTabWidth < this.preferredTabWidth){
25424 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25430 * Returns the number of tabs in this TabPanel.
25433 getCount : function(){
25434 return this.items.length;
25438 * Resizes all the tabs to the passed width
25439 * @param {Number} The new width
25441 setTabWidth : function(width){
25442 this.currentTabWidth = width;
25443 for(var i = 0, len = this.items.length; i < len; i++) {
25444 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25449 * Destroys this TabPanel
25450 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25452 destroy : function(removeEl){
25453 Roo.EventManager.removeResizeListener(this.onResize, this);
25454 for(var i = 0, len = this.items.length; i < len; i++){
25455 this.items[i].purgeListeners();
25457 if(removeEl === true){
25458 this.el.update("");
25465 * @class Roo.TabPanelItem
25466 * @extends Roo.util.Observable
25467 * Represents an individual item (tab plus body) in a TabPanel.
25468 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25469 * @param {String} id The id of this TabPanelItem
25470 * @param {String} text The text for the tab of this TabPanelItem
25471 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25473 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25475 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25476 * @type Roo.TabPanel
25478 this.tabPanel = tabPanel;
25480 * The id for this TabPanelItem
25485 this.disabled = false;
25489 this.loaded = false;
25490 this.closable = closable;
25493 * The body element for this TabPanelItem.
25494 * @type Roo.Element
25496 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25497 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25498 this.bodyEl.setStyle("display", "block");
25499 this.bodyEl.setStyle("zoom", "1");
25502 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25504 this.el = Roo.get(els.el, true);
25505 this.inner = Roo.get(els.inner, true);
25506 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25507 this.pnode = Roo.get(els.el.parentNode, true);
25508 this.el.on("mousedown", this.onTabMouseDown, this);
25509 this.el.on("click", this.onTabClick, this);
25512 var c = Roo.get(els.close, true);
25513 c.dom.title = this.closeText;
25514 c.addClassOnOver("close-over");
25515 c.on("click", this.closeClick, this);
25521 * Fires when this tab becomes the active tab.
25522 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25523 * @param {Roo.TabPanelItem} this
25527 * @event beforeclose
25528 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25529 * @param {Roo.TabPanelItem} this
25530 * @param {Object} e Set cancel to true on this object to cancel the close.
25532 "beforeclose": true,
25535 * Fires when this tab is closed.
25536 * @param {Roo.TabPanelItem} this
25540 * @event deactivate
25541 * Fires when this tab is no longer the active tab.
25542 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25543 * @param {Roo.TabPanelItem} this
25545 "deactivate" : true
25547 this.hidden = false;
25549 Roo.TabPanelItem.superclass.constructor.call(this);
25552 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25553 purgeListeners : function(){
25554 Roo.util.Observable.prototype.purgeListeners.call(this);
25555 this.el.removeAllListeners();
25558 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25561 this.pnode.addClass("on");
25564 this.tabPanel.stripWrap.repaint();
25566 this.fireEvent("activate", this.tabPanel, this);
25570 * Returns true if this tab is the active tab.
25571 * @return {Boolean}
25573 isActive : function(){
25574 return this.tabPanel.getActiveTab() == this;
25578 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25581 this.pnode.removeClass("on");
25583 this.fireEvent("deactivate", this.tabPanel, this);
25586 hideAction : function(){
25587 this.bodyEl.hide();
25588 this.bodyEl.setStyle("position", "absolute");
25589 this.bodyEl.setLeft("-20000px");
25590 this.bodyEl.setTop("-20000px");
25593 showAction : function(){
25594 this.bodyEl.setStyle("position", "relative");
25595 this.bodyEl.setTop("");
25596 this.bodyEl.setLeft("");
25597 this.bodyEl.show();
25601 * Set the tooltip for the tab.
25602 * @param {String} tooltip The tab's tooltip
25604 setTooltip : function(text){
25605 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25606 this.textEl.dom.qtip = text;
25607 this.textEl.dom.removeAttribute('title');
25609 this.textEl.dom.title = text;
25613 onTabClick : function(e){
25614 e.preventDefault();
25615 this.tabPanel.activate(this.id);
25618 onTabMouseDown : function(e){
25619 e.preventDefault();
25620 this.tabPanel.activate(this.id);
25623 getWidth : function(){
25624 return this.inner.getWidth();
25627 setWidth : function(width){
25628 var iwidth = width - this.pnode.getPadding("lr");
25629 this.inner.setWidth(iwidth);
25630 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25631 this.pnode.setWidth(width);
25635 * Show or hide the tab
25636 * @param {Boolean} hidden True to hide or false to show.
25638 setHidden : function(hidden){
25639 this.hidden = hidden;
25640 this.pnode.setStyle("display", hidden ? "none" : "");
25644 * Returns true if this tab is "hidden"
25645 * @return {Boolean}
25647 isHidden : function(){
25648 return this.hidden;
25652 * Returns the text for this tab
25655 getText : function(){
25659 autoSize : function(){
25660 //this.el.beginMeasure();
25661 this.textEl.setWidth(1);
25662 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25663 //this.el.endMeasure();
25667 * Sets the text for the tab (Note: this also sets the tooltip text)
25668 * @param {String} text The tab's text and tooltip
25670 setText : function(text){
25672 this.textEl.update(text);
25673 this.setTooltip(text);
25674 if(!this.tabPanel.resizeTabs){
25679 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25681 activate : function(){
25682 this.tabPanel.activate(this.id);
25686 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25688 disable : function(){
25689 if(this.tabPanel.active != this){
25690 this.disabled = true;
25691 this.pnode.addClass("disabled");
25696 * Enables this TabPanelItem if it was previously disabled.
25698 enable : function(){
25699 this.disabled = false;
25700 this.pnode.removeClass("disabled");
25704 * Sets the content for this TabPanelItem.
25705 * @param {String} content The content
25706 * @param {Boolean} loadScripts true to look for and load scripts
25708 setContent : function(content, loadScripts){
25709 this.bodyEl.update(content, loadScripts);
25713 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25714 * @return {Roo.UpdateManager} The UpdateManager
25716 getUpdateManager : function(){
25717 return this.bodyEl.getUpdateManager();
25721 * Set a URL to be used to load the content for this TabPanelItem.
25722 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25723 * @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)
25724 * @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)
25725 * @return {Roo.UpdateManager} The UpdateManager
25727 setUrl : function(url, params, loadOnce){
25728 if(this.refreshDelegate){
25729 this.un('activate', this.refreshDelegate);
25731 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25732 this.on("activate", this.refreshDelegate);
25733 return this.bodyEl.getUpdateManager();
25737 _handleRefresh : function(url, params, loadOnce){
25738 if(!loadOnce || !this.loaded){
25739 var updater = this.bodyEl.getUpdateManager();
25740 updater.update(url, params, this._setLoaded.createDelegate(this));
25745 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25746 * Will fail silently if the setUrl method has not been called.
25747 * This does not activate the panel, just updates its content.
25749 refresh : function(){
25750 if(this.refreshDelegate){
25751 this.loaded = false;
25752 this.refreshDelegate();
25757 _setLoaded : function(){
25758 this.loaded = true;
25762 closeClick : function(e){
25765 this.fireEvent("beforeclose", this, o);
25766 if(o.cancel !== true){
25767 this.tabPanel.removeTab(this.id);
25771 * The text displayed in the tooltip for the close icon.
25774 closeText : "Close this tab"
25778 Roo.TabPanel.prototype.createStrip = function(container){
25779 var strip = document.createElement("div");
25780 strip.className = "x-tabs-wrap";
25781 container.appendChild(strip);
25785 Roo.TabPanel.prototype.createStripList = function(strip){
25786 // div wrapper for retard IE
25787 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>';
25788 return strip.firstChild.firstChild.firstChild.firstChild;
25791 Roo.TabPanel.prototype.createBody = function(container){
25792 var body = document.createElement("div");
25793 Roo.id(body, "tab-body");
25794 Roo.fly(body).addClass("x-tabs-body");
25795 container.appendChild(body);
25799 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25800 var body = Roo.getDom(id);
25802 body = document.createElement("div");
25805 Roo.fly(body).addClass("x-tabs-item-body");
25806 bodyEl.insertBefore(body, bodyEl.firstChild);
25810 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25811 var td = document.createElement("td");
25812 stripEl.appendChild(td);
25814 td.className = "x-tabs-closable";
25815 if(!this.closeTpl){
25816 this.closeTpl = new Roo.Template(
25817 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25818 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25819 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25822 var el = this.closeTpl.overwrite(td, {"text": text});
25823 var close = el.getElementsByTagName("div")[0];
25824 var inner = el.getElementsByTagName("em")[0];
25825 return {"el": el, "close": close, "inner": inner};
25828 this.tabTpl = new Roo.Template(
25829 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25830 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25833 var el = this.tabTpl.overwrite(td, {"text": text});
25834 var inner = el.getElementsByTagName("em")[0];
25835 return {"el": el, "inner": inner};
25839 * Ext JS Library 1.1.1
25840 * Copyright(c) 2006-2007, Ext JS, LLC.
25842 * Originally Released Under LGPL - original licence link has changed is not relivant.
25845 * <script type="text/javascript">
25849 * @class Roo.Button
25850 * @extends Roo.util.Observable
25851 * Simple Button class
25852 * @cfg {String} text The button text
25853 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25854 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25855 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25856 * @cfg {Object} scope The scope of the handler
25857 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25858 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25859 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25860 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25861 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25862 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25863 applies if enableToggle = true)
25864 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25865 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25866 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25868 * Create a new button
25869 * @param {Object} config The config object
25871 Roo.Button = function(renderTo, config)
25875 renderTo = config.renderTo || false;
25878 Roo.apply(this, config);
25882 * Fires when this button is clicked
25883 * @param {Button} this
25884 * @param {EventObject} e The click event
25889 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25890 * @param {Button} this
25891 * @param {Boolean} pressed
25896 * Fires when the mouse hovers over the button
25897 * @param {Button} this
25898 * @param {Event} e The event object
25900 'mouseover' : true,
25903 * Fires when the mouse exits the button
25904 * @param {Button} this
25905 * @param {Event} e The event object
25910 * Fires when the button is rendered
25911 * @param {Button} this
25916 this.menu = Roo.menu.MenuMgr.get(this.menu);
25918 // register listeners first!! - so render can be captured..
25919 Roo.util.Observable.call(this);
25921 this.render(renderTo);
25927 Roo.extend(Roo.Button, Roo.util.Observable, {
25933 * Read-only. True if this button is hidden
25938 * Read-only. True if this button is disabled
25943 * Read-only. True if this button is pressed (only if enableToggle = true)
25949 * @cfg {Number} tabIndex
25950 * The DOM tabIndex for this button (defaults to undefined)
25952 tabIndex : undefined,
25955 * @cfg {Boolean} enableToggle
25956 * True to enable pressed/not pressed toggling (defaults to false)
25958 enableToggle: false,
25960 * @cfg {Mixed} menu
25961 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25965 * @cfg {String} menuAlign
25966 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25968 menuAlign : "tl-bl?",
25971 * @cfg {String} iconCls
25972 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25974 iconCls : undefined,
25976 * @cfg {String} type
25977 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25982 menuClassTarget: 'tr',
25985 * @cfg {String} clickEvent
25986 * The type of event to map to the button's event handler (defaults to 'click')
25988 clickEvent : 'click',
25991 * @cfg {Boolean} handleMouseEvents
25992 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25994 handleMouseEvents : true,
25997 * @cfg {String} tooltipType
25998 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26000 tooltipType : 'qtip',
26003 * @cfg {String} cls
26004 * A CSS class to apply to the button's main element.
26008 * @cfg {Roo.Template} template (Optional)
26009 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26010 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26011 * require code modifications if required elements (e.g. a button) aren't present.
26015 render : function(renderTo){
26017 if(this.hideParent){
26018 this.parentEl = Roo.get(renderTo);
26020 if(!this.dhconfig){
26021 if(!this.template){
26022 if(!Roo.Button.buttonTemplate){
26023 // hideous table template
26024 Roo.Button.buttonTemplate = new Roo.Template(
26025 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26026 '<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>',
26027 "</tr></tbody></table>");
26029 this.template = Roo.Button.buttonTemplate;
26031 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26032 var btnEl = btn.child("button:first");
26033 btnEl.on('focus', this.onFocus, this);
26034 btnEl.on('blur', this.onBlur, this);
26036 btn.addClass(this.cls);
26039 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26042 btnEl.addClass(this.iconCls);
26044 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26047 if(this.tabIndex !== undefined){
26048 btnEl.dom.tabIndex = this.tabIndex;
26051 if(typeof this.tooltip == 'object'){
26052 Roo.QuickTips.tips(Roo.apply({
26056 btnEl.dom[this.tooltipType] = this.tooltip;
26060 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26064 this.el.dom.id = this.el.id = this.id;
26067 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26068 this.menu.on("show", this.onMenuShow, this);
26069 this.menu.on("hide", this.onMenuHide, this);
26071 btn.addClass("x-btn");
26072 if(Roo.isIE && !Roo.isIE7){
26073 this.autoWidth.defer(1, this);
26077 if(this.handleMouseEvents){
26078 btn.on("mouseover", this.onMouseOver, this);
26079 btn.on("mouseout", this.onMouseOut, this);
26080 btn.on("mousedown", this.onMouseDown, this);
26082 btn.on(this.clickEvent, this.onClick, this);
26083 //btn.on("mouseup", this.onMouseUp, this);
26090 Roo.ButtonToggleMgr.register(this);
26092 this.el.addClass("x-btn-pressed");
26095 var repeater = new Roo.util.ClickRepeater(btn,
26096 typeof this.repeat == "object" ? this.repeat : {}
26098 repeater.on("click", this.onClick, this);
26101 this.fireEvent('render', this);
26105 * Returns the button's underlying element
26106 * @return {Roo.Element} The element
26108 getEl : function(){
26113 * Destroys this Button and removes any listeners.
26115 destroy : function(){
26116 Roo.ButtonToggleMgr.unregister(this);
26117 this.el.removeAllListeners();
26118 this.purgeListeners();
26123 autoWidth : function(){
26125 this.el.setWidth("auto");
26126 if(Roo.isIE7 && Roo.isStrict){
26127 var ib = this.el.child('button');
26128 if(ib && ib.getWidth() > 20){
26130 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26135 this.el.beginMeasure();
26137 if(this.el.getWidth() < this.minWidth){
26138 this.el.setWidth(this.minWidth);
26141 this.el.endMeasure();
26148 * Assigns this button's click handler
26149 * @param {Function} handler The function to call when the button is clicked
26150 * @param {Object} scope (optional) Scope for the function passed in
26152 setHandler : function(handler, scope){
26153 this.handler = handler;
26154 this.scope = scope;
26158 * Sets this button's text
26159 * @param {String} text The button text
26161 setText : function(text){
26164 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26170 * Gets the text for this button
26171 * @return {String} The button text
26173 getText : function(){
26181 this.hidden = false;
26183 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26191 this.hidden = true;
26193 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26198 * Convenience function for boolean show/hide
26199 * @param {Boolean} visible True to show, false to hide
26201 setVisible: function(visible){
26210 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26211 * @param {Boolean} state (optional) Force a particular state
26213 toggle : function(state){
26214 state = state === undefined ? !this.pressed : state;
26215 if(state != this.pressed){
26217 this.el.addClass("x-btn-pressed");
26218 this.pressed = true;
26219 this.fireEvent("toggle", this, true);
26221 this.el.removeClass("x-btn-pressed");
26222 this.pressed = false;
26223 this.fireEvent("toggle", this, false);
26225 if(this.toggleHandler){
26226 this.toggleHandler.call(this.scope || this, this, state);
26234 focus : function(){
26235 this.el.child('button:first').focus();
26239 * Disable this button
26241 disable : function(){
26243 this.el.addClass("x-btn-disabled");
26245 this.disabled = true;
26249 * Enable this button
26251 enable : function(){
26253 this.el.removeClass("x-btn-disabled");
26255 this.disabled = false;
26259 * Convenience function for boolean enable/disable
26260 * @param {Boolean} enabled True to enable, false to disable
26262 setDisabled : function(v){
26263 this[v !== true ? "enable" : "disable"]();
26267 onClick : function(e){
26269 e.preventDefault();
26274 if(!this.disabled){
26275 if(this.enableToggle){
26278 if(this.menu && !this.menu.isVisible()){
26279 this.menu.show(this.el, this.menuAlign);
26281 this.fireEvent("click", this, e);
26283 this.el.removeClass("x-btn-over");
26284 this.handler.call(this.scope || this, this, e);
26289 onMouseOver : function(e){
26290 if(!this.disabled){
26291 this.el.addClass("x-btn-over");
26292 this.fireEvent('mouseover', this, e);
26296 onMouseOut : function(e){
26297 if(!e.within(this.el, true)){
26298 this.el.removeClass("x-btn-over");
26299 this.fireEvent('mouseout', this, e);
26303 onFocus : function(e){
26304 if(!this.disabled){
26305 this.el.addClass("x-btn-focus");
26309 onBlur : function(e){
26310 this.el.removeClass("x-btn-focus");
26313 onMouseDown : function(e){
26314 if(!this.disabled && e.button == 0){
26315 this.el.addClass("x-btn-click");
26316 Roo.get(document).on('mouseup', this.onMouseUp, this);
26320 onMouseUp : function(e){
26322 this.el.removeClass("x-btn-click");
26323 Roo.get(document).un('mouseup', this.onMouseUp, this);
26327 onMenuShow : function(e){
26328 this.el.addClass("x-btn-menu-active");
26331 onMenuHide : function(e){
26332 this.el.removeClass("x-btn-menu-active");
26336 // Private utility class used by Button
26337 Roo.ButtonToggleMgr = function(){
26340 function toggleGroup(btn, state){
26342 var g = groups[btn.toggleGroup];
26343 for(var i = 0, l = g.length; i < l; i++){
26345 g[i].toggle(false);
26352 register : function(btn){
26353 if(!btn.toggleGroup){
26356 var g = groups[btn.toggleGroup];
26358 g = groups[btn.toggleGroup] = [];
26361 btn.on("toggle", toggleGroup);
26364 unregister : function(btn){
26365 if(!btn.toggleGroup){
26368 var g = groups[btn.toggleGroup];
26371 btn.un("toggle", toggleGroup);
26377 * Ext JS Library 1.1.1
26378 * Copyright(c) 2006-2007, Ext JS, LLC.
26380 * Originally Released Under LGPL - original licence link has changed is not relivant.
26383 * <script type="text/javascript">
26387 * @class Roo.SplitButton
26388 * @extends Roo.Button
26389 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26390 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26391 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26392 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26393 * @cfg {String} arrowTooltip The title attribute of the arrow
26395 * Create a new menu button
26396 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26397 * @param {Object} config The config object
26399 Roo.SplitButton = function(renderTo, config){
26400 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26402 * @event arrowclick
26403 * Fires when this button's arrow is clicked
26404 * @param {SplitButton} this
26405 * @param {EventObject} e The click event
26407 this.addEvents({"arrowclick":true});
26410 Roo.extend(Roo.SplitButton, Roo.Button, {
26411 render : function(renderTo){
26412 // this is one sweet looking template!
26413 var tpl = new Roo.Template(
26414 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26415 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26416 '<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>',
26417 "</tbody></table></td><td>",
26418 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26419 '<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>',
26420 "</tbody></table></td></tr></table>"
26422 var btn = tpl.append(renderTo, [this.text, this.type], true);
26423 var btnEl = btn.child("button");
26425 btn.addClass(this.cls);
26428 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26431 btnEl.addClass(this.iconCls);
26433 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26437 if(this.handleMouseEvents){
26438 btn.on("mouseover", this.onMouseOver, this);
26439 btn.on("mouseout", this.onMouseOut, this);
26440 btn.on("mousedown", this.onMouseDown, this);
26441 btn.on("mouseup", this.onMouseUp, this);
26443 btn.on(this.clickEvent, this.onClick, this);
26445 if(typeof this.tooltip == 'object'){
26446 Roo.QuickTips.tips(Roo.apply({
26450 btnEl.dom[this.tooltipType] = this.tooltip;
26453 if(this.arrowTooltip){
26454 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26463 this.el.addClass("x-btn-pressed");
26465 if(Roo.isIE && !Roo.isIE7){
26466 this.autoWidth.defer(1, this);
26471 this.menu.on("show", this.onMenuShow, this);
26472 this.menu.on("hide", this.onMenuHide, this);
26474 this.fireEvent('render', this);
26478 autoWidth : function(){
26480 var tbl = this.el.child("table:first");
26481 var tbl2 = this.el.child("table:last");
26482 this.el.setWidth("auto");
26483 tbl.setWidth("auto");
26484 if(Roo.isIE7 && Roo.isStrict){
26485 var ib = this.el.child('button:first');
26486 if(ib && ib.getWidth() > 20){
26488 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26493 this.el.beginMeasure();
26495 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26496 tbl.setWidth(this.minWidth-tbl2.getWidth());
26499 this.el.endMeasure();
26502 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26506 * Sets this button's click handler
26507 * @param {Function} handler The function to call when the button is clicked
26508 * @param {Object} scope (optional) Scope for the function passed above
26510 setHandler : function(handler, scope){
26511 this.handler = handler;
26512 this.scope = scope;
26516 * Sets this button's arrow click handler
26517 * @param {Function} handler The function to call when the arrow is clicked
26518 * @param {Object} scope (optional) Scope for the function passed above
26520 setArrowHandler : function(handler, scope){
26521 this.arrowHandler = handler;
26522 this.scope = scope;
26528 focus : function(){
26530 this.el.child("button:first").focus();
26535 onClick : function(e){
26536 e.preventDefault();
26537 if(!this.disabled){
26538 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26539 if(this.menu && !this.menu.isVisible()){
26540 this.menu.show(this.el, this.menuAlign);
26542 this.fireEvent("arrowclick", this, e);
26543 if(this.arrowHandler){
26544 this.arrowHandler.call(this.scope || this, this, e);
26547 this.fireEvent("click", this, e);
26549 this.handler.call(this.scope || this, this, e);
26555 onMouseDown : function(e){
26556 if(!this.disabled){
26557 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26561 onMouseUp : function(e){
26562 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26567 // backwards compat
26568 Roo.MenuButton = Roo.SplitButton;/*
26570 * Ext JS Library 1.1.1
26571 * Copyright(c) 2006-2007, Ext JS, LLC.
26573 * Originally Released Under LGPL - original licence link has changed is not relivant.
26576 * <script type="text/javascript">
26580 * @class Roo.Toolbar
26581 * Basic Toolbar class.
26583 * Creates a new Toolbar
26584 * @param {Object} config The config object
26586 Roo.Toolbar = function(container, buttons, config)
26588 /// old consturctor format still supported..
26589 if(container instanceof Array){ // omit the container for later rendering
26590 buttons = container;
26594 if (typeof(container) == 'object' && container.xtype) {
26595 config = container;
26596 container = config.container;
26597 buttons = config.buttons; // not really - use items!!
26600 if (config && config.items) {
26601 xitems = config.items;
26602 delete config.items;
26604 Roo.apply(this, config);
26605 this.buttons = buttons;
26608 this.render(container);
26610 Roo.each(xitems, function(b) {
26616 Roo.Toolbar.prototype = {
26618 * @cfg {Roo.data.Store} items
26619 * array of button configs or elements to add
26623 * @cfg {String/HTMLElement/Element} container
26624 * The id or element that will contain the toolbar
26627 render : function(ct){
26628 this.el = Roo.get(ct);
26630 this.el.addClass(this.cls);
26632 // using a table allows for vertical alignment
26633 // 100% width is needed by Safari...
26634 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26635 this.tr = this.el.child("tr", true);
26637 this.items = new Roo.util.MixedCollection(false, function(o){
26638 return o.id || ("item" + (++autoId));
26641 this.add.apply(this, this.buttons);
26642 delete this.buttons;
26647 * Adds element(s) to the toolbar -- this function takes a variable number of
26648 * arguments of mixed type and adds them to the toolbar.
26649 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26651 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26652 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26653 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26654 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26655 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26656 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26657 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26658 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26659 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26661 * @param {Mixed} arg2
26662 * @param {Mixed} etc.
26665 var a = arguments, l = a.length;
26666 for(var i = 0; i < l; i++){
26671 _add : function(el) {
26674 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26677 if (el.applyTo){ // some kind of form field
26678 return this.addField(el);
26680 if (el.render){ // some kind of Toolbar.Item
26681 return this.addItem(el);
26683 if (typeof el == "string"){ // string
26684 if(el == "separator" || el == "-"){
26685 return this.addSeparator();
26688 return this.addSpacer();
26691 return this.addFill();
26693 return this.addText(el);
26696 if(el.tagName){ // element
26697 return this.addElement(el);
26699 if(typeof el == "object"){ // must be button config?
26700 return this.addButton(el);
26702 // and now what?!?!
26708 * Add an Xtype element
26709 * @param {Object} xtype Xtype Object
26710 * @return {Object} created Object
26712 addxtype : function(e){
26713 return this.add(e);
26717 * Returns the Element for this toolbar.
26718 * @return {Roo.Element}
26720 getEl : function(){
26726 * @return {Roo.Toolbar.Item} The separator item
26728 addSeparator : function(){
26729 return this.addItem(new Roo.Toolbar.Separator());
26733 * Adds a spacer element
26734 * @return {Roo.Toolbar.Spacer} The spacer item
26736 addSpacer : function(){
26737 return this.addItem(new Roo.Toolbar.Spacer());
26741 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26742 * @return {Roo.Toolbar.Fill} The fill item
26744 addFill : function(){
26745 return this.addItem(new Roo.Toolbar.Fill());
26749 * Adds any standard HTML element to the toolbar
26750 * @param {String/HTMLElement/Element} el The element or id of the element to add
26751 * @return {Roo.Toolbar.Item} The element's item
26753 addElement : function(el){
26754 return this.addItem(new Roo.Toolbar.Item(el));
26757 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26758 * @type Roo.util.MixedCollection
26763 * Adds any Toolbar.Item or subclass
26764 * @param {Roo.Toolbar.Item} item
26765 * @return {Roo.Toolbar.Item} The item
26767 addItem : function(item){
26768 var td = this.nextBlock();
26770 this.items.add(item);
26775 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26776 * @param {Object/Array} config A button config or array of configs
26777 * @return {Roo.Toolbar.Button/Array}
26779 addButton : function(config){
26780 if(config instanceof Array){
26782 for(var i = 0, len = config.length; i < len; i++) {
26783 buttons.push(this.addButton(config[i]));
26788 if(!(config instanceof Roo.Toolbar.Button)){
26790 new Roo.Toolbar.SplitButton(config) :
26791 new Roo.Toolbar.Button(config);
26793 var td = this.nextBlock();
26800 * Adds text to the toolbar
26801 * @param {String} text The text to add
26802 * @return {Roo.Toolbar.Item} The element's item
26804 addText : function(text){
26805 return this.addItem(new Roo.Toolbar.TextItem(text));
26809 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26810 * @param {Number} index The index where the item is to be inserted
26811 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26812 * @return {Roo.Toolbar.Button/Item}
26814 insertButton : function(index, item){
26815 if(item instanceof Array){
26817 for(var i = 0, len = item.length; i < len; i++) {
26818 buttons.push(this.insertButton(index + i, item[i]));
26822 if (!(item instanceof Roo.Toolbar.Button)){
26823 item = new Roo.Toolbar.Button(item);
26825 var td = document.createElement("td");
26826 this.tr.insertBefore(td, this.tr.childNodes[index]);
26828 this.items.insert(index, item);
26833 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26834 * @param {Object} config
26835 * @return {Roo.Toolbar.Item} The element's item
26837 addDom : function(config, returnEl){
26838 var td = this.nextBlock();
26839 Roo.DomHelper.overwrite(td, config);
26840 var ti = new Roo.Toolbar.Item(td.firstChild);
26842 this.items.add(ti);
26847 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26848 * @type Roo.util.MixedCollection
26853 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26854 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26855 * @param {Roo.form.Field} field
26856 * @return {Roo.ToolbarItem}
26860 addField : function(field) {
26861 if (!this.fields) {
26863 this.fields = new Roo.util.MixedCollection(false, function(o){
26864 return o.id || ("item" + (++autoId));
26869 var td = this.nextBlock();
26871 var ti = new Roo.Toolbar.Item(td.firstChild);
26873 this.items.add(ti);
26874 this.fields.add(field);
26885 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26886 this.el.child('div').hide();
26894 this.el.child('div').show();
26898 nextBlock : function(){
26899 var td = document.createElement("td");
26900 this.tr.appendChild(td);
26905 destroy : function(){
26906 if(this.items){ // rendered?
26907 Roo.destroy.apply(Roo, this.items.items);
26909 if(this.fields){ // rendered?
26910 Roo.destroy.apply(Roo, this.fields.items);
26912 Roo.Element.uncache(this.el, this.tr);
26917 * @class Roo.Toolbar.Item
26918 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26920 * Creates a new Item
26921 * @param {HTMLElement} el
26923 Roo.Toolbar.Item = function(el){
26924 this.el = Roo.getDom(el);
26925 this.id = Roo.id(this.el);
26926 this.hidden = false;
26929 Roo.Toolbar.Item.prototype = {
26932 * Get this item's HTML Element
26933 * @return {HTMLElement}
26935 getEl : function(){
26940 render : function(td){
26942 td.appendChild(this.el);
26946 * Removes and destroys this item.
26948 destroy : function(){
26949 this.td.parentNode.removeChild(this.td);
26956 this.hidden = false;
26957 this.td.style.display = "";
26964 this.hidden = true;
26965 this.td.style.display = "none";
26969 * Convenience function for boolean show/hide.
26970 * @param {Boolean} visible true to show/false to hide
26972 setVisible: function(visible){
26981 * Try to focus this item.
26983 focus : function(){
26984 Roo.fly(this.el).focus();
26988 * Disables this item.
26990 disable : function(){
26991 Roo.fly(this.td).addClass("x-item-disabled");
26992 this.disabled = true;
26993 this.el.disabled = true;
26997 * Enables this item.
26999 enable : function(){
27000 Roo.fly(this.td).removeClass("x-item-disabled");
27001 this.disabled = false;
27002 this.el.disabled = false;
27008 * @class Roo.Toolbar.Separator
27009 * @extends Roo.Toolbar.Item
27010 * A simple toolbar separator class
27012 * Creates a new Separator
27014 Roo.Toolbar.Separator = function(){
27015 var s = document.createElement("span");
27016 s.className = "ytb-sep";
27017 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27019 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27020 enable:Roo.emptyFn,
27021 disable:Roo.emptyFn,
27026 * @class Roo.Toolbar.Spacer
27027 * @extends Roo.Toolbar.Item
27028 * A simple element that adds extra horizontal space to a toolbar.
27030 * Creates a new Spacer
27032 Roo.Toolbar.Spacer = function(){
27033 var s = document.createElement("div");
27034 s.className = "ytb-spacer";
27035 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27037 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27038 enable:Roo.emptyFn,
27039 disable:Roo.emptyFn,
27044 * @class Roo.Toolbar.Fill
27045 * @extends Roo.Toolbar.Spacer
27046 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27048 * Creates a new Spacer
27050 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27052 render : function(td){
27053 td.style.width = '100%';
27054 Roo.Toolbar.Fill.superclass.render.call(this, td);
27059 * @class Roo.Toolbar.TextItem
27060 * @extends Roo.Toolbar.Item
27061 * A simple class that renders text directly into a toolbar.
27063 * Creates a new TextItem
27064 * @param {String} text
27066 Roo.Toolbar.TextItem = function(text){
27067 if (typeof(text) == 'object') {
27070 var s = document.createElement("span");
27071 s.className = "ytb-text";
27072 s.innerHTML = text;
27073 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27075 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27076 enable:Roo.emptyFn,
27077 disable:Roo.emptyFn,
27082 * @class Roo.Toolbar.Button
27083 * @extends Roo.Button
27084 * A button that renders into a toolbar.
27086 * Creates a new Button
27087 * @param {Object} config A standard {@link Roo.Button} config object
27089 Roo.Toolbar.Button = function(config){
27090 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27092 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27093 render : function(td){
27095 Roo.Toolbar.Button.superclass.render.call(this, td);
27099 * Removes and destroys this button
27101 destroy : function(){
27102 Roo.Toolbar.Button.superclass.destroy.call(this);
27103 this.td.parentNode.removeChild(this.td);
27107 * Shows this button
27110 this.hidden = false;
27111 this.td.style.display = "";
27115 * Hides this button
27118 this.hidden = true;
27119 this.td.style.display = "none";
27123 * Disables this item
27125 disable : function(){
27126 Roo.fly(this.td).addClass("x-item-disabled");
27127 this.disabled = true;
27131 * Enables this item
27133 enable : function(){
27134 Roo.fly(this.td).removeClass("x-item-disabled");
27135 this.disabled = false;
27138 // backwards compat
27139 Roo.ToolbarButton = Roo.Toolbar.Button;
27142 * @class Roo.Toolbar.SplitButton
27143 * @extends Roo.SplitButton
27144 * A menu button that renders into a toolbar.
27146 * Creates a new SplitButton
27147 * @param {Object} config A standard {@link Roo.SplitButton} config object
27149 Roo.Toolbar.SplitButton = function(config){
27150 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27152 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27153 render : function(td){
27155 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27159 * Removes and destroys this button
27161 destroy : function(){
27162 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27163 this.td.parentNode.removeChild(this.td);
27167 * Shows this button
27170 this.hidden = false;
27171 this.td.style.display = "";
27175 * Hides this button
27178 this.hidden = true;
27179 this.td.style.display = "none";
27183 // backwards compat
27184 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27186 * Ext JS Library 1.1.1
27187 * Copyright(c) 2006-2007, Ext JS, LLC.
27189 * Originally Released Under LGPL - original licence link has changed is not relivant.
27192 * <script type="text/javascript">
27196 * @class Roo.PagingToolbar
27197 * @extends Roo.Toolbar
27198 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27200 * Create a new PagingToolbar
27201 * @param {Object} config The config object
27203 Roo.PagingToolbar = function(el, ds, config)
27205 // old args format still supported... - xtype is prefered..
27206 if (typeof(el) == 'object' && el.xtype) {
27207 // created from xtype...
27209 ds = el.dataSource;
27210 el = config.container;
27213 if (config.items) {
27214 items = config.items;
27218 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27221 this.renderButtons(this.el);
27224 // supprot items array.
27226 Roo.each(items, function(e) {
27227 this.add(Roo.factory(e));
27232 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27234 * @cfg {Roo.data.Store} dataSource
27235 * The underlying data store providing the paged data
27238 * @cfg {String/HTMLElement/Element} container
27239 * container The id or element that will contain the toolbar
27242 * @cfg {Boolean} displayInfo
27243 * True to display the displayMsg (defaults to false)
27246 * @cfg {Number} pageSize
27247 * The number of records to display per page (defaults to 20)
27251 * @cfg {String} displayMsg
27252 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27254 displayMsg : 'Displaying {0} - {1} of {2}',
27256 * @cfg {String} emptyMsg
27257 * The message to display when no records are found (defaults to "No data to display")
27259 emptyMsg : 'No data to display',
27261 * Customizable piece of the default paging text (defaults to "Page")
27264 beforePageText : "Page",
27266 * Customizable piece of the default paging text (defaults to "of %0")
27269 afterPageText : "of {0}",
27271 * Customizable piece of the default paging text (defaults to "First Page")
27274 firstText : "First Page",
27276 * Customizable piece of the default paging text (defaults to "Previous Page")
27279 prevText : "Previous Page",
27281 * Customizable piece of the default paging text (defaults to "Next Page")
27284 nextText : "Next Page",
27286 * Customizable piece of the default paging text (defaults to "Last Page")
27289 lastText : "Last Page",
27291 * Customizable piece of the default paging text (defaults to "Refresh")
27294 refreshText : "Refresh",
27297 renderButtons : function(el){
27298 Roo.PagingToolbar.superclass.render.call(this, el);
27299 this.first = this.addButton({
27300 tooltip: this.firstText,
27301 cls: "x-btn-icon x-grid-page-first",
27303 handler: this.onClick.createDelegate(this, ["first"])
27305 this.prev = this.addButton({
27306 tooltip: this.prevText,
27307 cls: "x-btn-icon x-grid-page-prev",
27309 handler: this.onClick.createDelegate(this, ["prev"])
27311 //this.addSeparator();
27312 this.add(this.beforePageText);
27313 this.field = Roo.get(this.addDom({
27318 cls: "x-grid-page-number"
27320 this.field.on("keydown", this.onPagingKeydown, this);
27321 this.field.on("focus", function(){this.dom.select();});
27322 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27323 this.field.setHeight(18);
27324 //this.addSeparator();
27325 this.next = this.addButton({
27326 tooltip: this.nextText,
27327 cls: "x-btn-icon x-grid-page-next",
27329 handler: this.onClick.createDelegate(this, ["next"])
27331 this.last = this.addButton({
27332 tooltip: this.lastText,
27333 cls: "x-btn-icon x-grid-page-last",
27335 handler: this.onClick.createDelegate(this, ["last"])
27337 //this.addSeparator();
27338 this.loading = this.addButton({
27339 tooltip: this.refreshText,
27340 cls: "x-btn-icon x-grid-loading",
27341 handler: this.onClick.createDelegate(this, ["refresh"])
27344 if(this.displayInfo){
27345 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27350 updateInfo : function(){
27351 if(this.displayEl){
27352 var count = this.ds.getCount();
27353 var msg = count == 0 ?
27357 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27359 this.displayEl.update(msg);
27364 onLoad : function(ds, r, o){
27365 this.cursor = o.params ? o.params.start : 0;
27366 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27368 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27369 this.field.dom.value = ap;
27370 this.first.setDisabled(ap == 1);
27371 this.prev.setDisabled(ap == 1);
27372 this.next.setDisabled(ap == ps);
27373 this.last.setDisabled(ap == ps);
27374 this.loading.enable();
27379 getPageData : function(){
27380 var total = this.ds.getTotalCount();
27383 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27384 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27389 onLoadError : function(){
27390 this.loading.enable();
27394 onPagingKeydown : function(e){
27395 var k = e.getKey();
27396 var d = this.getPageData();
27398 var v = this.field.dom.value, pageNum;
27399 if(!v || isNaN(pageNum = parseInt(v, 10))){
27400 this.field.dom.value = d.activePage;
27403 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27404 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27407 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))
27409 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27410 this.field.dom.value = pageNum;
27411 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27414 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27416 var v = this.field.dom.value, pageNum;
27417 var increment = (e.shiftKey) ? 10 : 1;
27418 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27420 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27421 this.field.dom.value = d.activePage;
27424 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27426 this.field.dom.value = parseInt(v, 10) + increment;
27427 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27428 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27435 beforeLoad : function(){
27437 this.loading.disable();
27442 onClick : function(which){
27446 ds.load({params:{start: 0, limit: this.pageSize}});
27449 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27452 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27455 var total = ds.getTotalCount();
27456 var extra = total % this.pageSize;
27457 var lastStart = extra ? (total - extra) : total-this.pageSize;
27458 ds.load({params:{start: lastStart, limit: this.pageSize}});
27461 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27467 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27468 * @param {Roo.data.Store} store The data store to unbind
27470 unbind : function(ds){
27471 ds.un("beforeload", this.beforeLoad, this);
27472 ds.un("load", this.onLoad, this);
27473 ds.un("loadexception", this.onLoadError, this);
27474 ds.un("remove", this.updateInfo, this);
27475 ds.un("add", this.updateInfo, this);
27476 this.ds = undefined;
27480 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27481 * @param {Roo.data.Store} store The data store to bind
27483 bind : function(ds){
27484 ds.on("beforeload", this.beforeLoad, this);
27485 ds.on("load", this.onLoad, this);
27486 ds.on("loadexception", this.onLoadError, this);
27487 ds.on("remove", this.updateInfo, this);
27488 ds.on("add", this.updateInfo, this);
27493 * Ext JS Library 1.1.1
27494 * Copyright(c) 2006-2007, Ext JS, LLC.
27496 * Originally Released Under LGPL - original licence link has changed is not relivant.
27499 * <script type="text/javascript">
27503 * @class Roo.Resizable
27504 * @extends Roo.util.Observable
27505 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27506 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27507 * 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
27508 * the element will be wrapped for you automatically.</p>
27509 * <p>Here is the list of valid resize handles:</p>
27512 ------ -------------------
27521 'hd' horizontal drag
27524 * <p>Here's an example showing the creation of a typical Resizable:</p>
27526 var resizer = new Roo.Resizable("element-id", {
27534 resizer.on("resize", myHandler);
27536 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27537 * resizer.east.setDisplayed(false);</p>
27538 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27539 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27540 * resize operation's new size (defaults to [0, 0])
27541 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27542 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27543 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27544 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27545 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27546 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27547 * @cfg {Number} width The width of the element in pixels (defaults to null)
27548 * @cfg {Number} height The height of the element in pixels (defaults to null)
27549 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27550 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27551 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27552 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27553 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27554 * in favor of the handles config option (defaults to false)
27555 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27556 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27557 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27558 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27559 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27560 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27561 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27562 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27563 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27564 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27565 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27567 * Create a new resizable component
27568 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27569 * @param {Object} config configuration options
27571 Roo.Resizable = function(el, config)
27573 this.el = Roo.get(el);
27575 if(config && config.wrap){
27576 config.resizeChild = this.el;
27577 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27578 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27579 this.el.setStyle("overflow", "hidden");
27580 this.el.setPositioning(config.resizeChild.getPositioning());
27581 config.resizeChild.clearPositioning();
27582 if(!config.width || !config.height){
27583 var csize = config.resizeChild.getSize();
27584 this.el.setSize(csize.width, csize.height);
27586 if(config.pinned && !config.adjustments){
27587 config.adjustments = "auto";
27591 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27592 this.proxy.unselectable();
27593 this.proxy.enableDisplayMode('block');
27595 Roo.apply(this, config);
27598 this.disableTrackOver = true;
27599 this.el.addClass("x-resizable-pinned");
27601 // if the element isn't positioned, make it relative
27602 var position = this.el.getStyle("position");
27603 if(position != "absolute" && position != "fixed"){
27604 this.el.setStyle("position", "relative");
27606 if(!this.handles){ // no handles passed, must be legacy style
27607 this.handles = 's,e,se';
27608 if(this.multiDirectional){
27609 this.handles += ',n,w';
27612 if(this.handles == "all"){
27613 this.handles = "n s e w ne nw se sw";
27615 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27616 var ps = Roo.Resizable.positions;
27617 for(var i = 0, len = hs.length; i < len; i++){
27618 if(hs[i] && ps[hs[i]]){
27619 var pos = ps[hs[i]];
27620 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27624 this.corner = this.southeast;
27626 // updateBox = the box can move..
27627 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27628 this.updateBox = true;
27631 this.activeHandle = null;
27633 if(this.resizeChild){
27634 if(typeof this.resizeChild == "boolean"){
27635 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27637 this.resizeChild = Roo.get(this.resizeChild, true);
27641 if(this.adjustments == "auto"){
27642 var rc = this.resizeChild;
27643 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27644 if(rc && (hw || hn)){
27645 rc.position("relative");
27646 rc.setLeft(hw ? hw.el.getWidth() : 0);
27647 rc.setTop(hn ? hn.el.getHeight() : 0);
27649 this.adjustments = [
27650 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27651 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27655 if(this.draggable){
27656 this.dd = this.dynamic ?
27657 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27658 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27664 * @event beforeresize
27665 * Fired before resize is allowed. Set enabled to false to cancel resize.
27666 * @param {Roo.Resizable} this
27667 * @param {Roo.EventObject} e The mousedown event
27669 "beforeresize" : true,
27672 * Fired after a resize.
27673 * @param {Roo.Resizable} this
27674 * @param {Number} width The new width
27675 * @param {Number} height The new height
27676 * @param {Roo.EventObject} e The mouseup event
27681 if(this.width !== null && this.height !== null){
27682 this.resizeTo(this.width, this.height);
27684 this.updateChildSize();
27687 this.el.dom.style.zoom = 1;
27689 Roo.Resizable.superclass.constructor.call(this);
27692 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27693 resizeChild : false,
27694 adjustments : [0, 0],
27704 multiDirectional : false,
27705 disableTrackOver : false,
27706 easing : 'easeOutStrong',
27707 widthIncrement : 0,
27708 heightIncrement : 0,
27712 preserveRatio : false,
27713 transparent: false,
27719 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27721 constrainTo: undefined,
27723 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27725 resizeRegion: undefined,
27729 * Perform a manual resize
27730 * @param {Number} width
27731 * @param {Number} height
27733 resizeTo : function(width, height){
27734 this.el.setSize(width, height);
27735 this.updateChildSize();
27736 this.fireEvent("resize", this, width, height, null);
27740 startSizing : function(e, handle){
27741 this.fireEvent("beforeresize", this, e);
27742 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27745 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27746 this.overlay.unselectable();
27747 this.overlay.enableDisplayMode("block");
27748 this.overlay.on("mousemove", this.onMouseMove, this);
27749 this.overlay.on("mouseup", this.onMouseUp, this);
27751 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27753 this.resizing = true;
27754 this.startBox = this.el.getBox();
27755 this.startPoint = e.getXY();
27756 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27757 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27759 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27760 this.overlay.show();
27762 if(this.constrainTo) {
27763 var ct = Roo.get(this.constrainTo);
27764 this.resizeRegion = ct.getRegion().adjust(
27765 ct.getFrameWidth('t'),
27766 ct.getFrameWidth('l'),
27767 -ct.getFrameWidth('b'),
27768 -ct.getFrameWidth('r')
27772 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27774 this.proxy.setBox(this.startBox);
27776 this.proxy.setStyle('visibility', 'visible');
27782 onMouseDown : function(handle, e){
27785 this.activeHandle = handle;
27786 this.startSizing(e, handle);
27791 onMouseUp : function(e){
27792 var size = this.resizeElement();
27793 this.resizing = false;
27795 this.overlay.hide();
27797 this.fireEvent("resize", this, size.width, size.height, e);
27801 updateChildSize : function(){
27802 if(this.resizeChild){
27804 var child = this.resizeChild;
27805 var adj = this.adjustments;
27806 if(el.dom.offsetWidth){
27807 var b = el.getSize(true);
27808 child.setSize(b.width+adj[0], b.height+adj[1]);
27810 // Second call here for IE
27811 // The first call enables instant resizing and
27812 // the second call corrects scroll bars if they
27815 setTimeout(function(){
27816 if(el.dom.offsetWidth){
27817 var b = el.getSize(true);
27818 child.setSize(b.width+adj[0], b.height+adj[1]);
27826 snap : function(value, inc, min){
27827 if(!inc || !value) return value;
27828 var newValue = value;
27829 var m = value % inc;
27832 newValue = value + (inc-m);
27834 newValue = value - m;
27837 return Math.max(min, newValue);
27841 resizeElement : function(){
27842 var box = this.proxy.getBox();
27843 if(this.updateBox){
27844 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27846 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27848 this.updateChildSize();
27856 constrain : function(v, diff, m, mx){
27859 }else if(v - diff > mx){
27866 onMouseMove : function(e){
27868 try{// try catch so if something goes wrong the user doesn't get hung
27870 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27874 //var curXY = this.startPoint;
27875 var curSize = this.curSize || this.startBox;
27876 var x = this.startBox.x, y = this.startBox.y;
27877 var ox = x, oy = y;
27878 var w = curSize.width, h = curSize.height;
27879 var ow = w, oh = h;
27880 var mw = this.minWidth, mh = this.minHeight;
27881 var mxw = this.maxWidth, mxh = this.maxHeight;
27882 var wi = this.widthIncrement;
27883 var hi = this.heightIncrement;
27885 var eventXY = e.getXY();
27886 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27887 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27889 var pos = this.activeHandle.position;
27894 w = Math.min(Math.max(mw, w), mxw);
27899 h = Math.min(Math.max(mh, h), mxh);
27904 w = Math.min(Math.max(mw, w), mxw);
27905 h = Math.min(Math.max(mh, h), mxh);
27908 diffY = this.constrain(h, diffY, mh, mxh);
27915 var adiffX = Math.abs(diffX);
27916 var sub = (adiffX % wi); // how much
27917 if (sub > (wi/2)) { // far enough to snap
27918 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
27920 // remove difference..
27921 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
27925 x = Math.max(this.minX, x);
27928 diffX = this.constrain(w, diffX, mw, mxw);
27934 w = Math.min(Math.max(mw, w), mxw);
27935 diffY = this.constrain(h, diffY, mh, mxh);
27940 diffX = this.constrain(w, diffX, mw, mxw);
27941 diffY = this.constrain(h, diffY, mh, mxh);
27948 diffX = this.constrain(w, diffX, mw, mxw);
27950 h = Math.min(Math.max(mh, h), mxh);
27956 var sw = this.snap(w, wi, mw);
27957 var sh = this.snap(h, hi, mh);
27958 if(sw != w || sh != h){
27981 if(this.preserveRatio){
27986 h = Math.min(Math.max(mh, h), mxh);
27991 w = Math.min(Math.max(mw, w), mxw);
27996 w = Math.min(Math.max(mw, w), mxw);
28002 w = Math.min(Math.max(mw, w), mxw);
28008 h = Math.min(Math.max(mh, h), mxh);
28016 h = Math.min(Math.max(mh, h), mxh);
28026 h = Math.min(Math.max(mh, h), mxh);
28034 if (pos == 'hdrag') {
28037 this.proxy.setBounds(x, y, w, h);
28039 this.resizeElement();
28046 handleOver : function(){
28048 this.el.addClass("x-resizable-over");
28053 handleOut : function(){
28054 if(!this.resizing){
28055 this.el.removeClass("x-resizable-over");
28060 * Returns the element this component is bound to.
28061 * @return {Roo.Element}
28063 getEl : function(){
28068 * Returns the resizeChild element (or null).
28069 * @return {Roo.Element}
28071 getResizeChild : function(){
28072 return this.resizeChild;
28076 * Destroys this resizable. If the element was wrapped and
28077 * removeEl is not true then the element remains.
28078 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28080 destroy : function(removeEl){
28081 this.proxy.remove();
28083 this.overlay.removeAllListeners();
28084 this.overlay.remove();
28086 var ps = Roo.Resizable.positions;
28088 if(typeof ps[k] != "function" && this[ps[k]]){
28089 var h = this[ps[k]];
28090 h.el.removeAllListeners();
28095 this.el.update("");
28102 // hash to map config positions to true positions
28103 Roo.Resizable.positions = {
28104 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28109 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28111 // only initialize the template if resizable is used
28112 var tpl = Roo.DomHelper.createTemplate(
28113 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28116 Roo.Resizable.Handle.prototype.tpl = tpl;
28118 this.position = pos;
28120 // show north drag fro topdra
28121 var handlepos = pos == 'hdrag' ? 'north' : pos;
28123 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28124 if (pos == 'hdrag') {
28125 this.el.setStyle('cursor', 'pointer');
28127 this.el.unselectable();
28129 this.el.setOpacity(0);
28131 this.el.on("mousedown", this.onMouseDown, this);
28132 if(!disableTrackOver){
28133 this.el.on("mouseover", this.onMouseOver, this);
28134 this.el.on("mouseout", this.onMouseOut, this);
28139 Roo.Resizable.Handle.prototype = {
28140 afterResize : function(rz){
28144 onMouseDown : function(e){
28145 this.rz.onMouseDown(this, e);
28148 onMouseOver : function(e){
28149 this.rz.handleOver(this, e);
28152 onMouseOut : function(e){
28153 this.rz.handleOut(this, e);
28157 * Ext JS Library 1.1.1
28158 * Copyright(c) 2006-2007, Ext JS, LLC.
28160 * Originally Released Under LGPL - original licence link has changed is not relivant.
28163 * <script type="text/javascript">
28167 * @class Roo.Editor
28168 * @extends Roo.Component
28169 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28171 * Create a new Editor
28172 * @param {Roo.form.Field} field The Field object (or descendant)
28173 * @param {Object} config The config object
28175 Roo.Editor = function(field, config){
28176 Roo.Editor.superclass.constructor.call(this, config);
28177 this.field = field;
28180 * @event beforestartedit
28181 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28182 * false from the handler of this event.
28183 * @param {Editor} this
28184 * @param {Roo.Element} boundEl The underlying element bound to this editor
28185 * @param {Mixed} value The field value being set
28187 "beforestartedit" : true,
28190 * Fires when this editor is displayed
28191 * @param {Roo.Element} boundEl The underlying element bound to this editor
28192 * @param {Mixed} value The starting field value
28194 "startedit" : true,
28196 * @event beforecomplete
28197 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28198 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28199 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28200 * event will not fire since no edit actually occurred.
28201 * @param {Editor} this
28202 * @param {Mixed} value The current field value
28203 * @param {Mixed} startValue The original field value
28205 "beforecomplete" : true,
28208 * Fires after editing is complete and any changed value has been written to the underlying field.
28209 * @param {Editor} this
28210 * @param {Mixed} value The current field value
28211 * @param {Mixed} startValue The original field value
28215 * @event specialkey
28216 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28217 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28218 * @param {Roo.form.Field} this
28219 * @param {Roo.EventObject} e The event object
28221 "specialkey" : true
28225 Roo.extend(Roo.Editor, Roo.Component, {
28227 * @cfg {Boolean/String} autosize
28228 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28229 * or "height" to adopt the height only (defaults to false)
28232 * @cfg {Boolean} revertInvalid
28233 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28234 * validation fails (defaults to true)
28237 * @cfg {Boolean} ignoreNoChange
28238 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28239 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28240 * will never be ignored.
28243 * @cfg {Boolean} hideEl
28244 * False to keep the bound element visible while the editor is displayed (defaults to true)
28247 * @cfg {Mixed} value
28248 * The data value of the underlying field (defaults to "")
28252 * @cfg {String} alignment
28253 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28257 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28258 * for bottom-right shadow (defaults to "frame")
28262 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28266 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28268 completeOnEnter : false,
28270 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28272 cancelOnEsc : false,
28274 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28279 onRender : function(ct, position){
28280 this.el = new Roo.Layer({
28281 shadow: this.shadow,
28287 constrain: this.constrain
28289 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28290 if(this.field.msgTarget != 'title'){
28291 this.field.msgTarget = 'qtip';
28293 this.field.render(this.el);
28295 this.field.el.dom.setAttribute('autocomplete', 'off');
28297 this.field.on("specialkey", this.onSpecialKey, this);
28298 if(this.swallowKeys){
28299 this.field.el.swallowEvent(['keydown','keypress']);
28302 this.field.on("blur", this.onBlur, this);
28303 if(this.field.grow){
28304 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28308 onSpecialKey : function(field, e){
28309 //Roo.log('editor onSpecialKey');
28310 if(this.completeOnEnter && e.getKey() == e.ENTER){
28312 this.completeEdit();
28313 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
28316 this.fireEvent('specialkey', field, e);
28321 * Starts the editing process and shows the editor.
28322 * @param {String/HTMLElement/Element} el The element to edit
28323 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28324 * to the innerHTML of el.
28326 startEdit : function(el, value){
28328 this.completeEdit();
28330 this.boundEl = Roo.get(el);
28331 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28332 if(!this.rendered){
28333 this.render(this.parentEl || document.body);
28335 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28338 this.startValue = v;
28339 this.field.setValue(v);
28341 var sz = this.boundEl.getSize();
28342 switch(this.autoSize){
28344 this.setSize(sz.width, "");
28347 this.setSize("", sz.height);
28350 this.setSize(sz.width, sz.height);
28353 this.el.alignTo(this.boundEl, this.alignment);
28354 this.editing = true;
28356 Roo.QuickTips.disable();
28362 * Sets the height and width of this editor.
28363 * @param {Number} width The new width
28364 * @param {Number} height The new height
28366 setSize : function(w, h){
28367 this.field.setSize(w, h);
28374 * Realigns the editor to the bound field based on the current alignment config value.
28376 realign : function(){
28377 this.el.alignTo(this.boundEl, this.alignment);
28381 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28382 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28384 completeEdit : function(remainVisible){
28388 var v = this.getValue();
28389 if(this.revertInvalid !== false && !this.field.isValid()){
28390 v = this.startValue;
28391 this.cancelEdit(true);
28393 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28394 this.editing = false;
28398 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28399 this.editing = false;
28400 if(this.updateEl && this.boundEl){
28401 this.boundEl.update(v);
28403 if(remainVisible !== true){
28406 this.fireEvent("complete", this, v, this.startValue);
28411 onShow : function(){
28413 if(this.hideEl !== false){
28414 this.boundEl.hide();
28417 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28418 this.fixIEFocus = true;
28419 this.deferredFocus.defer(50, this);
28421 this.field.focus();
28423 this.fireEvent("startedit", this.boundEl, this.startValue);
28426 deferredFocus : function(){
28428 this.field.focus();
28433 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28434 * reverted to the original starting value.
28435 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28436 * cancel (defaults to false)
28438 cancelEdit : function(remainVisible){
28440 this.setValue(this.startValue);
28441 if(remainVisible !== true){
28448 onBlur : function(){
28449 if(this.allowBlur !== true && this.editing){
28450 this.completeEdit();
28455 onHide : function(){
28457 this.completeEdit();
28461 if(this.field.collapse){
28462 this.field.collapse();
28465 if(this.hideEl !== false){
28466 this.boundEl.show();
28469 Roo.QuickTips.enable();
28474 * Sets the data value of the editor
28475 * @param {Mixed} value Any valid value supported by the underlying field
28477 setValue : function(v){
28478 this.field.setValue(v);
28482 * Gets the data value of the editor
28483 * @return {Mixed} The data value
28485 getValue : function(){
28486 return this.field.getValue();
28490 * Ext JS Library 1.1.1
28491 * Copyright(c) 2006-2007, Ext JS, LLC.
28493 * Originally Released Under LGPL - original licence link has changed is not relivant.
28496 * <script type="text/javascript">
28500 * @class Roo.BasicDialog
28501 * @extends Roo.util.Observable
28502 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28504 var dlg = new Roo.BasicDialog("my-dlg", {
28513 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28514 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28515 dlg.addButton('Cancel', dlg.hide, dlg);
28518 <b>A Dialog should always be a direct child of the body element.</b>
28519 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28520 * @cfg {String} title Default text to display in the title bar (defaults to null)
28521 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28522 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28523 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28524 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28525 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28526 * (defaults to null with no animation)
28527 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28528 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28529 * property for valid values (defaults to 'all')
28530 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28531 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28532 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28533 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28534 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28535 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28536 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28537 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28538 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28539 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28540 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28541 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28542 * draggable = true (defaults to false)
28543 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28544 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28545 * shadow (defaults to false)
28546 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28547 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28548 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28549 * @cfg {Array} buttons Array of buttons
28550 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28552 * Create a new BasicDialog.
28553 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28554 * @param {Object} config Configuration options
28556 Roo.BasicDialog = function(el, config){
28557 this.el = Roo.get(el);
28558 var dh = Roo.DomHelper;
28559 if(!this.el && config && config.autoCreate){
28560 if(typeof config.autoCreate == "object"){
28561 if(!config.autoCreate.id){
28562 config.autoCreate.id = el;
28564 this.el = dh.append(document.body,
28565 config.autoCreate, true);
28567 this.el = dh.append(document.body,
28568 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28572 el.setDisplayed(true);
28573 el.hide = this.hideAction;
28575 el.addClass("x-dlg");
28577 Roo.apply(this, config);
28579 this.proxy = el.createProxy("x-dlg-proxy");
28580 this.proxy.hide = this.hideAction;
28581 this.proxy.setOpacity(.5);
28585 el.setWidth(config.width);
28588 el.setHeight(config.height);
28590 this.size = el.getSize();
28591 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28592 this.xy = [config.x,config.y];
28594 this.xy = el.getCenterXY(true);
28596 /** The header element @type Roo.Element */
28597 this.header = el.child("> .x-dlg-hd");
28598 /** The body element @type Roo.Element */
28599 this.body = el.child("> .x-dlg-bd");
28600 /** The footer element @type Roo.Element */
28601 this.footer = el.child("> .x-dlg-ft");
28604 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28607 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28610 this.header.unselectable();
28612 this.header.update(this.title);
28614 // this element allows the dialog to be focused for keyboard event
28615 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28616 this.focusEl.swallowEvent("click", true);
28618 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28620 // wrap the body and footer for special rendering
28621 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28623 this.bwrap.dom.appendChild(this.footer.dom);
28626 this.bg = this.el.createChild({
28627 tag: "div", cls:"x-dlg-bg",
28628 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28630 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28633 if(this.autoScroll !== false && !this.autoTabs){
28634 this.body.setStyle("overflow", "auto");
28637 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28639 if(this.closable !== false){
28640 this.el.addClass("x-dlg-closable");
28641 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28642 this.close.on("click", this.closeClick, this);
28643 this.close.addClassOnOver("x-dlg-close-over");
28645 if(this.collapsible !== false){
28646 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28647 this.collapseBtn.on("click", this.collapseClick, this);
28648 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28649 this.header.on("dblclick", this.collapseClick, this);
28651 if(this.resizable !== false){
28652 this.el.addClass("x-dlg-resizable");
28653 this.resizer = new Roo.Resizable(el, {
28654 minWidth: this.minWidth || 80,
28655 minHeight:this.minHeight || 80,
28656 handles: this.resizeHandles || "all",
28659 this.resizer.on("beforeresize", this.beforeResize, this);
28660 this.resizer.on("resize", this.onResize, this);
28662 if(this.draggable !== false){
28663 el.addClass("x-dlg-draggable");
28664 if (!this.proxyDrag) {
28665 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28668 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28670 dd.setHandleElId(this.header.id);
28671 dd.endDrag = this.endMove.createDelegate(this);
28672 dd.startDrag = this.startMove.createDelegate(this);
28673 dd.onDrag = this.onDrag.createDelegate(this);
28678 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28679 this.mask.enableDisplayMode("block");
28681 this.el.addClass("x-dlg-modal");
28684 this.shadow = new Roo.Shadow({
28685 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28686 offset : this.shadowOffset
28689 this.shadowOffset = 0;
28691 if(Roo.useShims && this.shim !== false){
28692 this.shim = this.el.createShim();
28693 this.shim.hide = this.hideAction;
28701 if (this.buttons) {
28702 var bts= this.buttons;
28704 Roo.each(bts, function(b) {
28713 * Fires when a key is pressed
28714 * @param {Roo.BasicDialog} this
28715 * @param {Roo.EventObject} e
28720 * Fires when this dialog is moved by the user.
28721 * @param {Roo.BasicDialog} this
28722 * @param {Number} x The new page X
28723 * @param {Number} y The new page Y
28728 * Fires when this dialog is resized by the user.
28729 * @param {Roo.BasicDialog} this
28730 * @param {Number} width The new width
28731 * @param {Number} height The new height
28735 * @event beforehide
28736 * Fires before this dialog is hidden.
28737 * @param {Roo.BasicDialog} this
28739 "beforehide" : true,
28742 * Fires when this dialog is hidden.
28743 * @param {Roo.BasicDialog} this
28747 * @event beforeshow
28748 * Fires before this dialog is shown.
28749 * @param {Roo.BasicDialog} this
28751 "beforeshow" : true,
28754 * Fires when this dialog is shown.
28755 * @param {Roo.BasicDialog} this
28759 el.on("keydown", this.onKeyDown, this);
28760 el.on("mousedown", this.toFront, this);
28761 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28763 Roo.DialogManager.register(this);
28764 Roo.BasicDialog.superclass.constructor.call(this);
28767 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28768 shadowOffset: Roo.isIE ? 6 : 5,
28771 minButtonWidth: 75,
28772 defaultButton: null,
28773 buttonAlign: "right",
28778 * Sets the dialog title text
28779 * @param {String} text The title text to display
28780 * @return {Roo.BasicDialog} this
28782 setTitle : function(text){
28783 this.header.update(text);
28788 closeClick : function(){
28793 collapseClick : function(){
28794 this[this.collapsed ? "expand" : "collapse"]();
28798 * Collapses the dialog to its minimized state (only the title bar is visible).
28799 * Equivalent to the user clicking the collapse dialog button.
28801 collapse : function(){
28802 if(!this.collapsed){
28803 this.collapsed = true;
28804 this.el.addClass("x-dlg-collapsed");
28805 this.restoreHeight = this.el.getHeight();
28806 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28811 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28812 * clicking the expand dialog button.
28814 expand : function(){
28815 if(this.collapsed){
28816 this.collapsed = false;
28817 this.el.removeClass("x-dlg-collapsed");
28818 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28823 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28824 * @return {Roo.TabPanel} The tabs component
28826 initTabs : function(){
28827 var tabs = this.getTabs();
28828 while(tabs.getTab(0)){
28831 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28833 tabs.addTab(Roo.id(dom), dom.title);
28841 beforeResize : function(){
28842 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28846 onResize : function(){
28847 this.refreshSize();
28848 this.syncBodyHeight();
28849 this.adjustAssets();
28851 this.fireEvent("resize", this, this.size.width, this.size.height);
28855 onKeyDown : function(e){
28856 if(this.isVisible()){
28857 this.fireEvent("keydown", this, e);
28862 * Resizes the dialog.
28863 * @param {Number} width
28864 * @param {Number} height
28865 * @return {Roo.BasicDialog} this
28867 resizeTo : function(width, height){
28868 this.el.setSize(width, height);
28869 this.size = {width: width, height: height};
28870 this.syncBodyHeight();
28871 if(this.fixedcenter){
28874 if(this.isVisible()){
28875 this.constrainXY();
28876 this.adjustAssets();
28878 this.fireEvent("resize", this, width, height);
28884 * Resizes the dialog to fit the specified content size.
28885 * @param {Number} width
28886 * @param {Number} height
28887 * @return {Roo.BasicDialog} this
28889 setContentSize : function(w, h){
28890 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28891 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28892 //if(!this.el.isBorderBox()){
28893 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28894 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28897 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28898 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28900 this.resizeTo(w, h);
28905 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28906 * executed in response to a particular key being pressed while the dialog is active.
28907 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28908 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28909 * @param {Function} fn The function to call
28910 * @param {Object} scope (optional) The scope of the function
28911 * @return {Roo.BasicDialog} this
28913 addKeyListener : function(key, fn, scope){
28914 var keyCode, shift, ctrl, alt;
28915 if(typeof key == "object" && !(key instanceof Array)){
28916 keyCode = key["key"];
28917 shift = key["shift"];
28918 ctrl = key["ctrl"];
28923 var handler = function(dlg, e){
28924 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28925 var k = e.getKey();
28926 if(keyCode instanceof Array){
28927 for(var i = 0, len = keyCode.length; i < len; i++){
28928 if(keyCode[i] == k){
28929 fn.call(scope || window, dlg, k, e);
28935 fn.call(scope || window, dlg, k, e);
28940 this.on("keydown", handler);
28945 * Returns the TabPanel component (creates it if it doesn't exist).
28946 * Note: If you wish to simply check for the existence of tabs without creating them,
28947 * check for a null 'tabs' property.
28948 * @return {Roo.TabPanel} The tabs component
28950 getTabs : function(){
28952 this.el.addClass("x-dlg-auto-tabs");
28953 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28954 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28960 * Adds a button to the footer section of the dialog.
28961 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28962 * object or a valid Roo.DomHelper element config
28963 * @param {Function} handler The function called when the button is clicked
28964 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28965 * @return {Roo.Button} The new button
28967 addButton : function(config, handler, scope){
28968 var dh = Roo.DomHelper;
28970 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28972 if(!this.btnContainer){
28973 var tb = this.footer.createChild({
28975 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28976 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28978 this.btnContainer = tb.firstChild.firstChild.firstChild;
28983 minWidth: this.minButtonWidth,
28986 if(typeof config == "string"){
28987 bconfig.text = config;
28990 bconfig.dhconfig = config;
28992 Roo.apply(bconfig, config);
28996 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28997 bconfig.position = Math.max(0, bconfig.position);
28998 fc = this.btnContainer.childNodes[bconfig.position];
29001 var btn = new Roo.Button(
29003 this.btnContainer.insertBefore(document.createElement("td"),fc)
29004 : this.btnContainer.appendChild(document.createElement("td")),
29005 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29008 this.syncBodyHeight();
29011 * Array of all the buttons that have been added to this dialog via addButton
29016 this.buttons.push(btn);
29021 * Sets the default button to be focused when the dialog is displayed.
29022 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29023 * @return {Roo.BasicDialog} this
29025 setDefaultButton : function(btn){
29026 this.defaultButton = btn;
29031 getHeaderFooterHeight : function(safe){
29034 height += this.header.getHeight();
29037 var fm = this.footer.getMargins();
29038 height += (this.footer.getHeight()+fm.top+fm.bottom);
29040 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29041 height += this.centerBg.getPadding("tb");
29046 syncBodyHeight : function(){
29047 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29048 var height = this.size.height - this.getHeaderFooterHeight(false);
29049 bd.setHeight(height-bd.getMargins("tb"));
29050 var hh = this.header.getHeight();
29051 var h = this.size.height-hh;
29053 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29054 bw.setHeight(h-cb.getPadding("tb"));
29055 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29056 bd.setWidth(bw.getWidth(true));
29058 this.tabs.syncHeight();
29060 this.tabs.el.repaint();
29066 * Restores the previous state of the dialog if Roo.state is configured.
29067 * @return {Roo.BasicDialog} this
29069 restoreState : function(){
29070 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29071 if(box && box.width){
29072 this.xy = [box.x, box.y];
29073 this.resizeTo(box.width, box.height);
29079 beforeShow : function(){
29081 if(this.fixedcenter){
29082 this.xy = this.el.getCenterXY(true);
29085 Roo.get(document.body).addClass("x-body-masked");
29086 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29089 this.constrainXY();
29093 animShow : function(){
29094 var b = Roo.get(this.animateTarget).getBox();
29095 this.proxy.setSize(b.width, b.height);
29096 this.proxy.setLocation(b.x, b.y);
29098 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29099 true, .35, this.showEl.createDelegate(this));
29103 * Shows the dialog.
29104 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29105 * @return {Roo.BasicDialog} this
29107 show : function(animateTarget){
29108 if (this.fireEvent("beforeshow", this) === false){
29111 if(this.syncHeightBeforeShow){
29112 this.syncBodyHeight();
29113 }else if(this.firstShow){
29114 this.firstShow = false;
29115 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29117 this.animateTarget = animateTarget || this.animateTarget;
29118 if(!this.el.isVisible()){
29120 if(this.animateTarget && Roo.get(this.animateTarget)){
29130 showEl : function(){
29132 this.el.setXY(this.xy);
29134 this.adjustAssets(true);
29137 // IE peekaboo bug - fix found by Dave Fenwick
29141 this.fireEvent("show", this);
29145 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29146 * dialog itself will receive focus.
29148 focus : function(){
29149 if(this.defaultButton){
29150 this.defaultButton.focus();
29152 this.focusEl.focus();
29157 constrainXY : function(){
29158 if(this.constraintoviewport !== false){
29159 if(!this.viewSize){
29160 if(this.container){
29161 var s = this.container.getSize();
29162 this.viewSize = [s.width, s.height];
29164 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29167 var s = Roo.get(this.container||document).getScroll();
29169 var x = this.xy[0], y = this.xy[1];
29170 var w = this.size.width, h = this.size.height;
29171 var vw = this.viewSize[0], vh = this.viewSize[1];
29172 // only move it if it needs it
29174 // first validate right/bottom
29175 if(x + w > vw+s.left){
29179 if(y + h > vh+s.top){
29183 // then make sure top/left isn't negative
29195 if(this.isVisible()){
29196 this.el.setLocation(x, y);
29197 this.adjustAssets();
29204 onDrag : function(){
29205 if(!this.proxyDrag){
29206 this.xy = this.el.getXY();
29207 this.adjustAssets();
29212 adjustAssets : function(doShow){
29213 var x = this.xy[0], y = this.xy[1];
29214 var w = this.size.width, h = this.size.height;
29215 if(doShow === true){
29217 this.shadow.show(this.el);
29223 if(this.shadow && this.shadow.isVisible()){
29224 this.shadow.show(this.el);
29226 if(this.shim && this.shim.isVisible()){
29227 this.shim.setBounds(x, y, w, h);
29232 adjustViewport : function(w, h){
29234 w = Roo.lib.Dom.getViewWidth();
29235 h = Roo.lib.Dom.getViewHeight();
29238 this.viewSize = [w, h];
29239 if(this.modal && this.mask.isVisible()){
29240 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29241 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29243 if(this.isVisible()){
29244 this.constrainXY();
29249 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29250 * shadow, proxy, mask, etc.) Also removes all event listeners.
29251 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29253 destroy : function(removeEl){
29254 if(this.isVisible()){
29255 this.animateTarget = null;
29258 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29260 this.tabs.destroy(removeEl);
29273 for(var i = 0, len = this.buttons.length; i < len; i++){
29274 this.buttons[i].destroy();
29277 this.el.removeAllListeners();
29278 if(removeEl === true){
29279 this.el.update("");
29282 Roo.DialogManager.unregister(this);
29286 startMove : function(){
29287 if(this.proxyDrag){
29290 if(this.constraintoviewport !== false){
29291 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29296 endMove : function(){
29297 if(!this.proxyDrag){
29298 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29300 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29303 this.refreshSize();
29304 this.adjustAssets();
29306 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29310 * Brings this dialog to the front of any other visible dialogs
29311 * @return {Roo.BasicDialog} this
29313 toFront : function(){
29314 Roo.DialogManager.bringToFront(this);
29319 * Sends this dialog to the back (under) of any other visible dialogs
29320 * @return {Roo.BasicDialog} this
29322 toBack : function(){
29323 Roo.DialogManager.sendToBack(this);
29328 * Centers this dialog in the viewport
29329 * @return {Roo.BasicDialog} this
29331 center : function(){
29332 var xy = this.el.getCenterXY(true);
29333 this.moveTo(xy[0], xy[1]);
29338 * Moves the dialog's top-left corner to the specified point
29339 * @param {Number} x
29340 * @param {Number} y
29341 * @return {Roo.BasicDialog} this
29343 moveTo : function(x, y){
29345 if(this.isVisible()){
29346 this.el.setXY(this.xy);
29347 this.adjustAssets();
29353 * Aligns the dialog to the specified element
29354 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29355 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29356 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29357 * @return {Roo.BasicDialog} this
29359 alignTo : function(element, position, offsets){
29360 this.xy = this.el.getAlignToXY(element, position, offsets);
29361 if(this.isVisible()){
29362 this.el.setXY(this.xy);
29363 this.adjustAssets();
29369 * Anchors an element to another element and realigns it when the window is resized.
29370 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29371 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29372 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29373 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29374 * is a number, it is used as the buffer delay (defaults to 50ms).
29375 * @return {Roo.BasicDialog} this
29377 anchorTo : function(el, alignment, offsets, monitorScroll){
29378 var action = function(){
29379 this.alignTo(el, alignment, offsets);
29381 Roo.EventManager.onWindowResize(action, this);
29382 var tm = typeof monitorScroll;
29383 if(tm != 'undefined'){
29384 Roo.EventManager.on(window, 'scroll', action, this,
29385 {buffer: tm == 'number' ? monitorScroll : 50});
29392 * Returns true if the dialog is visible
29393 * @return {Boolean}
29395 isVisible : function(){
29396 return this.el.isVisible();
29400 animHide : function(callback){
29401 var b = Roo.get(this.animateTarget).getBox();
29403 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29405 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29406 this.hideEl.createDelegate(this, [callback]));
29410 * Hides the dialog.
29411 * @param {Function} callback (optional) Function to call when the dialog is hidden
29412 * @return {Roo.BasicDialog} this
29414 hide : function(callback){
29415 if (this.fireEvent("beforehide", this) === false){
29419 this.shadow.hide();
29424 // sometimes animateTarget seems to get set.. causing problems...
29425 // this just double checks..
29426 if(this.animateTarget && Roo.get(this.animateTarget)) {
29427 this.animHide(callback);
29430 this.hideEl(callback);
29436 hideEl : function(callback){
29440 Roo.get(document.body).removeClass("x-body-masked");
29442 this.fireEvent("hide", this);
29443 if(typeof callback == "function"){
29449 hideAction : function(){
29450 this.setLeft("-10000px");
29451 this.setTop("-10000px");
29452 this.setStyle("visibility", "hidden");
29456 refreshSize : function(){
29457 this.size = this.el.getSize();
29458 this.xy = this.el.getXY();
29459 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29463 // z-index is managed by the DialogManager and may be overwritten at any time
29464 setZIndex : function(index){
29466 this.mask.setStyle("z-index", index);
29469 this.shim.setStyle("z-index", ++index);
29472 this.shadow.setZIndex(++index);
29474 this.el.setStyle("z-index", ++index);
29476 this.proxy.setStyle("z-index", ++index);
29479 this.resizer.proxy.setStyle("z-index", ++index);
29482 this.lastZIndex = index;
29486 * Returns the element for this dialog
29487 * @return {Roo.Element} The underlying dialog Element
29489 getEl : function(){
29495 * @class Roo.DialogManager
29496 * Provides global access to BasicDialogs that have been created and
29497 * support for z-indexing (layering) multiple open dialogs.
29499 Roo.DialogManager = function(){
29501 var accessList = [];
29505 var sortDialogs = function(d1, d2){
29506 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29510 var orderDialogs = function(){
29511 accessList.sort(sortDialogs);
29512 var seed = Roo.DialogManager.zseed;
29513 for(var i = 0, len = accessList.length; i < len; i++){
29514 var dlg = accessList[i];
29516 dlg.setZIndex(seed + (i*10));
29523 * The starting z-index for BasicDialogs (defaults to 9000)
29524 * @type Number The z-index value
29529 register : function(dlg){
29530 list[dlg.id] = dlg;
29531 accessList.push(dlg);
29535 unregister : function(dlg){
29536 delete list[dlg.id];
29539 if(!accessList.indexOf){
29540 for( i = 0, len = accessList.length; i < len; i++){
29541 if(accessList[i] == dlg){
29542 accessList.splice(i, 1);
29547 i = accessList.indexOf(dlg);
29549 accessList.splice(i, 1);
29555 * Gets a registered dialog by id
29556 * @param {String/Object} id The id of the dialog or a dialog
29557 * @return {Roo.BasicDialog} this
29559 get : function(id){
29560 return typeof id == "object" ? id : list[id];
29564 * Brings the specified dialog to the front
29565 * @param {String/Object} dlg The id of the dialog or a dialog
29566 * @return {Roo.BasicDialog} this
29568 bringToFront : function(dlg){
29569 dlg = this.get(dlg);
29572 dlg._lastAccess = new Date().getTime();
29579 * Sends the specified dialog to the back
29580 * @param {String/Object} dlg The id of the dialog or a dialog
29581 * @return {Roo.BasicDialog} this
29583 sendToBack : function(dlg){
29584 dlg = this.get(dlg);
29585 dlg._lastAccess = -(new Date().getTime());
29591 * Hides all dialogs
29593 hideAll : function(){
29594 for(var id in list){
29595 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29604 * @class Roo.LayoutDialog
29605 * @extends Roo.BasicDialog
29606 * Dialog which provides adjustments for working with a layout in a Dialog.
29607 * Add your necessary layout config options to the dialog's config.<br>
29608 * Example usage (including a nested layout):
29611 dialog = new Roo.LayoutDialog("download-dlg", {
29620 // layout config merges with the dialog config
29622 tabPosition: "top",
29623 alwaysShowTabs: true
29626 dialog.addKeyListener(27, dialog.hide, dialog);
29627 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29628 dialog.addButton("Build It!", this.getDownload, this);
29630 // we can even add nested layouts
29631 var innerLayout = new Roo.BorderLayout("dl-inner", {
29641 innerLayout.beginUpdate();
29642 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29643 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29644 innerLayout.endUpdate(true);
29646 var layout = dialog.getLayout();
29647 layout.beginUpdate();
29648 layout.add("center", new Roo.ContentPanel("standard-panel",
29649 {title: "Download the Source", fitToFrame:true}));
29650 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29651 {title: "Build your own roo.js"}));
29652 layout.getRegion("center").showPanel(sp);
29653 layout.endUpdate();
29657 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29658 * @param {Object} config configuration options
29660 Roo.LayoutDialog = function(el, cfg){
29663 if (typeof(cfg) == 'undefined') {
29664 config = Roo.apply({}, el);
29665 // not sure why we use documentElement here.. - it should always be body.
29666 // IE7 borks horribly if we use documentElement.
29667 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
29668 //config.autoCreate = true;
29672 config.autoTabs = false;
29673 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29674 this.body.setStyle({overflow:"hidden", position:"relative"});
29675 this.layout = new Roo.BorderLayout(this.body.dom, config);
29676 this.layout.monitorWindowResize = false;
29677 this.el.addClass("x-dlg-auto-layout");
29678 // fix case when center region overwrites center function
29679 this.center = Roo.BasicDialog.prototype.center;
29680 this.on("show", this.layout.layout, this.layout, true);
29681 if (config.items) {
29682 var xitems = config.items;
29683 delete config.items;
29684 Roo.each(xitems, this.addxtype, this);
29689 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29691 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29694 endUpdate : function(){
29695 this.layout.endUpdate();
29699 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29702 beginUpdate : function(){
29703 this.layout.beginUpdate();
29707 * Get the BorderLayout for this dialog
29708 * @return {Roo.BorderLayout}
29710 getLayout : function(){
29711 return this.layout;
29714 showEl : function(){
29715 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29717 this.layout.layout();
29722 // Use the syncHeightBeforeShow config option to control this automatically
29723 syncBodyHeight : function(){
29724 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29725 if(this.layout){this.layout.layout();}
29729 * Add an xtype element (actually adds to the layout.)
29730 * @return {Object} xdata xtype object data.
29733 addxtype : function(c) {
29734 return this.layout.addxtype(c);
29738 * Ext JS Library 1.1.1
29739 * Copyright(c) 2006-2007, Ext JS, LLC.
29741 * Originally Released Under LGPL - original licence link has changed is not relivant.
29744 * <script type="text/javascript">
29748 * @class Roo.MessageBox
29749 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29753 Roo.Msg.alert('Status', 'Changes saved successfully.');
29755 // Prompt for user data:
29756 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29758 // process text value...
29762 // Show a dialog using config options:
29764 title:'Save Changes?',
29765 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29766 buttons: Roo.Msg.YESNOCANCEL,
29773 Roo.MessageBox = function(){
29774 var dlg, opt, mask, waitTimer;
29775 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29776 var buttons, activeTextEl, bwidth;
29779 var handleButton = function(button){
29781 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29785 var handleHide = function(){
29786 if(opt && opt.cls){
29787 dlg.el.removeClass(opt.cls);
29790 Roo.TaskMgr.stop(waitTimer);
29796 var updateButtons = function(b){
29799 buttons["ok"].hide();
29800 buttons["cancel"].hide();
29801 buttons["yes"].hide();
29802 buttons["no"].hide();
29803 dlg.footer.dom.style.display = 'none';
29806 dlg.footer.dom.style.display = '';
29807 for(var k in buttons){
29808 if(typeof buttons[k] != "function"){
29811 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29812 width += buttons[k].el.getWidth()+15;
29822 var handleEsc = function(d, k, e){
29823 if(opt && opt.closable !== false){
29833 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29834 * @return {Roo.BasicDialog} The BasicDialog element
29836 getDialog : function(){
29838 dlg = new Roo.BasicDialog("x-msg-box", {
29843 constraintoviewport:false,
29845 collapsible : false,
29848 width:400, height:100,
29849 buttonAlign:"center",
29850 closeClick : function(){
29851 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29852 handleButton("no");
29854 handleButton("cancel");
29858 dlg.on("hide", handleHide);
29860 dlg.addKeyListener(27, handleEsc);
29862 var bt = this.buttonText;
29863 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29864 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29865 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29866 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29867 bodyEl = dlg.body.createChild({
29869 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>'
29871 msgEl = bodyEl.dom.firstChild;
29872 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29873 textboxEl.enableDisplayMode();
29874 textboxEl.addKeyListener([10,13], function(){
29875 if(dlg.isVisible() && opt && opt.buttons){
29876 if(opt.buttons.ok){
29877 handleButton("ok");
29878 }else if(opt.buttons.yes){
29879 handleButton("yes");
29883 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29884 textareaEl.enableDisplayMode();
29885 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29886 progressEl.enableDisplayMode();
29887 var pf = progressEl.dom.firstChild;
29889 pp = Roo.get(pf.firstChild);
29890 pp.setHeight(pf.offsetHeight);
29898 * Updates the message box body text
29899 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29900 * the XHTML-compliant non-breaking space character '&#160;')
29901 * @return {Roo.MessageBox} This message box
29903 updateText : function(text){
29904 if(!dlg.isVisible() && !opt.width){
29905 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29907 msgEl.innerHTML = text || ' ';
29908 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29909 Math.max(opt.minWidth || this.minWidth, bwidth));
29911 activeTextEl.setWidth(w);
29913 if(dlg.isVisible()){
29914 dlg.fixedcenter = false;
29916 dlg.setContentSize(w, bodyEl.getHeight());
29917 if(dlg.isVisible()){
29918 dlg.fixedcenter = true;
29924 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29925 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29926 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29927 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29928 * @return {Roo.MessageBox} This message box
29930 updateProgress : function(value, text){
29932 this.updateText(text);
29934 if (pp) { // weird bug on my firefox - for some reason this is not defined
29935 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29941 * Returns true if the message box is currently displayed
29942 * @return {Boolean} True if the message box is visible, else false
29944 isVisible : function(){
29945 return dlg && dlg.isVisible();
29949 * Hides the message box if it is displayed
29952 if(this.isVisible()){
29958 * Displays a new message box, or reinitializes an existing message box, based on the config options
29959 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29960 * The following config object properties are supported:
29962 Property Type Description
29963 ---------- --------------- ------------------------------------------------------------------------------------
29964 animEl String/Element An id or Element from which the message box should animate as it opens and
29965 closes (defaults to undefined)
29966 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29967 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29968 closable Boolean False to hide the top-right close button (defaults to true). Note that
29969 progress and wait dialogs will ignore this property and always hide the
29970 close button as they can only be closed programmatically.
29971 cls String A custom CSS class to apply to the message box element
29972 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29973 displayed (defaults to 75)
29974 fn Function A callback function to execute after closing the dialog. The arguments to the
29975 function will be btn (the name of the button that was clicked, if applicable,
29976 e.g. "ok"), and text (the value of the active text field, if applicable).
29977 Progress and wait dialogs will ignore this option since they do not respond to
29978 user actions and can only be closed programmatically, so any required function
29979 should be called by the same code after it closes the dialog.
29980 icon String A CSS class that provides a background image to be used as an icon for
29981 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29982 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29983 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29984 modal Boolean False to allow user interaction with the page while the message box is
29985 displayed (defaults to true)
29986 msg String A string that will replace the existing message box body text (defaults
29987 to the XHTML-compliant non-breaking space character ' ')
29988 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29989 progress Boolean True to display a progress bar (defaults to false)
29990 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29991 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29992 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29993 title String The title text
29994 value String The string value to set into the active textbox element if displayed
29995 wait Boolean True to display a progress bar (defaults to false)
29996 width Number The width of the dialog in pixels
30003 msg: 'Please enter your address:',
30005 buttons: Roo.MessageBox.OKCANCEL,
30008 animEl: 'addAddressBtn'
30011 * @param {Object} config Configuration options
30012 * @return {Roo.MessageBox} This message box
30014 show : function(options){
30015 if(this.isVisible()){
30018 var d = this.getDialog();
30020 d.setTitle(opt.title || " ");
30021 d.close.setDisplayed(opt.closable !== false);
30022 activeTextEl = textboxEl;
30023 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30028 textareaEl.setHeight(typeof opt.multiline == "number" ?
30029 opt.multiline : this.defaultTextHeight);
30030 activeTextEl = textareaEl;
30039 progressEl.setDisplayed(opt.progress === true);
30040 this.updateProgress(0);
30041 activeTextEl.dom.value = opt.value || "";
30043 dlg.setDefaultButton(activeTextEl);
30045 var bs = opt.buttons;
30048 db = buttons["ok"];
30049 }else if(bs && bs.yes){
30050 db = buttons["yes"];
30052 dlg.setDefaultButton(db);
30054 bwidth = updateButtons(opt.buttons);
30055 this.updateText(opt.msg);
30057 d.el.addClass(opt.cls);
30059 d.proxyDrag = opt.proxyDrag === true;
30060 d.modal = opt.modal !== false;
30061 d.mask = opt.modal !== false ? mask : false;
30062 if(!d.isVisible()){
30063 // force it to the end of the z-index stack so it gets a cursor in FF
30064 document.body.appendChild(dlg.el.dom);
30065 d.animateTarget = null;
30066 d.show(options.animEl);
30072 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30073 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30074 * and closing the message box when the process is complete.
30075 * @param {String} title The title bar text
30076 * @param {String} msg The message box body text
30077 * @return {Roo.MessageBox} This message box
30079 progress : function(title, msg){
30086 minWidth: this.minProgressWidth,
30093 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30094 * If a callback function is passed it will be called after the user clicks the button, and the
30095 * id of the button that was clicked will be passed as the only parameter to the callback
30096 * (could also be the top-right close button).
30097 * @param {String} title The title bar text
30098 * @param {String} msg The message box body text
30099 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30100 * @param {Object} scope (optional) The scope of the callback function
30101 * @return {Roo.MessageBox} This message box
30103 alert : function(title, msg, fn, scope){
30116 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30117 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30118 * You are responsible for closing the message box when the process is complete.
30119 * @param {String} msg The message box body text
30120 * @param {String} title (optional) The title bar text
30121 * @return {Roo.MessageBox} This message box
30123 wait : function(msg, title){
30134 waitTimer = Roo.TaskMgr.start({
30136 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30144 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30145 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30146 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30147 * @param {String} title The title bar text
30148 * @param {String} msg The message box body text
30149 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30150 * @param {Object} scope (optional) The scope of the callback function
30151 * @return {Roo.MessageBox} This message box
30153 confirm : function(title, msg, fn, scope){
30157 buttons: this.YESNO,
30166 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30167 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30168 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30169 * (could also be the top-right close button) and the text that was entered will be passed as the two
30170 * parameters to the callback.
30171 * @param {String} title The title bar text
30172 * @param {String} msg The message box body text
30173 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30174 * @param {Object} scope (optional) The scope of the callback function
30175 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30176 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30177 * @return {Roo.MessageBox} This message box
30179 prompt : function(title, msg, fn, scope, multiline){
30183 buttons: this.OKCANCEL,
30188 multiline: multiline,
30195 * Button config that displays a single OK button
30200 * Button config that displays Yes and No buttons
30203 YESNO : {yes:true, no:true},
30205 * Button config that displays OK and Cancel buttons
30208 OKCANCEL : {ok:true, cancel:true},
30210 * Button config that displays Yes, No and Cancel buttons
30213 YESNOCANCEL : {yes:true, no:true, cancel:true},
30216 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30219 defaultTextHeight : 75,
30221 * The maximum width in pixels of the message box (defaults to 600)
30226 * The minimum width in pixels of the message box (defaults to 100)
30231 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30232 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30235 minProgressWidth : 250,
30237 * An object containing the default button text strings that can be overriden for localized language support.
30238 * Supported properties are: ok, cancel, yes and no.
30239 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30252 * Shorthand for {@link Roo.MessageBox}
30254 Roo.Msg = Roo.MessageBox;/*
30256 * Ext JS Library 1.1.1
30257 * Copyright(c) 2006-2007, Ext JS, LLC.
30259 * Originally Released Under LGPL - original licence link has changed is not relivant.
30262 * <script type="text/javascript">
30265 * @class Roo.QuickTips
30266 * Provides attractive and customizable tooltips for any element.
30269 Roo.QuickTips = function(){
30270 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30271 var ce, bd, xy, dd;
30272 var visible = false, disabled = true, inited = false;
30273 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30275 var onOver = function(e){
30279 var t = e.getTarget();
30280 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30283 if(ce && t == ce.el){
30284 clearTimeout(hideProc);
30287 if(t && tagEls[t.id]){
30288 tagEls[t.id].el = t;
30289 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30292 var ttp, et = Roo.fly(t);
30293 var ns = cfg.namespace;
30294 if(tm.interceptTitles && t.title){
30297 t.removeAttribute("title");
30298 e.preventDefault();
30300 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30303 showProc = show.defer(tm.showDelay, tm, [{
30306 width: et.getAttributeNS(ns, cfg.width),
30307 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30308 title: et.getAttributeNS(ns, cfg.title),
30309 cls: et.getAttributeNS(ns, cfg.cls)
30314 var onOut = function(e){
30315 clearTimeout(showProc);
30316 var t = e.getTarget();
30317 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30318 hideProc = setTimeout(hide, tm.hideDelay);
30322 var onMove = function(e){
30328 if(tm.trackMouse && ce){
30333 var onDown = function(e){
30334 clearTimeout(showProc);
30335 clearTimeout(hideProc);
30337 if(tm.hideOnClick){
30340 tm.enable.defer(100, tm);
30345 var getPad = function(){
30346 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30349 var show = function(o){
30353 clearTimeout(dismissProc);
30355 if(removeCls){ // in case manually hidden
30356 el.removeClass(removeCls);
30360 el.addClass(ce.cls);
30361 removeCls = ce.cls;
30364 tipTitle.update(ce.title);
30367 tipTitle.update('');
30370 el.dom.style.width = tm.maxWidth+'px';
30371 //tipBody.dom.style.width = '';
30372 tipBodyText.update(o.text);
30373 var p = getPad(), w = ce.width;
30375 var td = tipBodyText.dom;
30376 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30377 if(aw > tm.maxWidth){
30379 }else if(aw < tm.minWidth){
30385 //tipBody.setWidth(w);
30386 el.setWidth(parseInt(w, 10) + p);
30387 if(ce.autoHide === false){
30388 close.setDisplayed(true);
30393 close.setDisplayed(false);
30399 el.avoidY = xy[1]-18;
30404 el.setStyle("visibility", "visible");
30405 el.fadeIn({callback: afterShow});
30411 var afterShow = function(){
30415 if(tm.autoDismiss && ce.autoHide !== false){
30416 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30421 var hide = function(noanim){
30422 clearTimeout(dismissProc);
30423 clearTimeout(hideProc);
30425 if(el.isVisible()){
30427 if(noanim !== true && tm.animate){
30428 el.fadeOut({callback: afterHide});
30435 var afterHide = function(){
30438 el.removeClass(removeCls);
30445 * @cfg {Number} minWidth
30446 * The minimum width of the quick tip (defaults to 40)
30450 * @cfg {Number} maxWidth
30451 * The maximum width of the quick tip (defaults to 300)
30455 * @cfg {Boolean} interceptTitles
30456 * True to automatically use the element's DOM title value if available (defaults to false)
30458 interceptTitles : false,
30460 * @cfg {Boolean} trackMouse
30461 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30463 trackMouse : false,
30465 * @cfg {Boolean} hideOnClick
30466 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30468 hideOnClick : true,
30470 * @cfg {Number} showDelay
30471 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30475 * @cfg {Number} hideDelay
30476 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30480 * @cfg {Boolean} autoHide
30481 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30482 * Used in conjunction with hideDelay.
30487 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30488 * (defaults to true). Used in conjunction with autoDismissDelay.
30490 autoDismiss : true,
30493 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30495 autoDismissDelay : 5000,
30497 * @cfg {Boolean} animate
30498 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30503 * @cfg {String} title
30504 * Title text to display (defaults to ''). This can be any valid HTML markup.
30508 * @cfg {String} text
30509 * Body text to display (defaults to ''). This can be any valid HTML markup.
30513 * @cfg {String} cls
30514 * A CSS class to apply to the base quick tip element (defaults to '').
30518 * @cfg {Number} width
30519 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30520 * minWidth or maxWidth.
30525 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30526 * or display QuickTips in a page.
30529 tm = Roo.QuickTips;
30530 cfg = tm.tagConfig;
30532 if(!Roo.isReady){ // allow calling of init() before onReady
30533 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30536 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30537 el.fxDefaults = {stopFx: true};
30538 // maximum custom styling
30539 //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>');
30540 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>');
30541 tipTitle = el.child('h3');
30542 tipTitle.enableDisplayMode("block");
30543 tipBody = el.child('div.x-tip-bd');
30544 tipBodyText = el.child('div.x-tip-bd-inner');
30545 //bdLeft = el.child('div.x-tip-bd-left');
30546 //bdRight = el.child('div.x-tip-bd-right');
30547 close = el.child('div.x-tip-close');
30548 close.enableDisplayMode("block");
30549 close.on("click", hide);
30550 var d = Roo.get(document);
30551 d.on("mousedown", onDown);
30552 d.on("mouseover", onOver);
30553 d.on("mouseout", onOut);
30554 d.on("mousemove", onMove);
30555 esc = d.addKeyListener(27, hide);
30558 dd = el.initDD("default", null, {
30559 onDrag : function(){
30563 dd.setHandleElId(tipTitle.id);
30572 * Configures a new quick tip instance and assigns it to a target element. The following config options
30575 Property Type Description
30576 ---------- --------------------- ------------------------------------------------------------------------
30577 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30579 * @param {Object} config The config object
30581 register : function(config){
30582 var cs = config instanceof Array ? config : arguments;
30583 for(var i = 0, len = cs.length; i < len; i++) {
30585 var target = c.target;
30587 if(target instanceof Array){
30588 for(var j = 0, jlen = target.length; j < jlen; j++){
30589 tagEls[target[j]] = c;
30592 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30599 * Removes this quick tip from its element and destroys it.
30600 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30602 unregister : function(el){
30603 delete tagEls[Roo.id(el)];
30607 * Enable this quick tip.
30609 enable : function(){
30610 if(inited && disabled){
30612 if(locks.length < 1){
30619 * Disable this quick tip.
30621 disable : function(){
30623 clearTimeout(showProc);
30624 clearTimeout(hideProc);
30625 clearTimeout(dismissProc);
30633 * Returns true if the quick tip is enabled, else false.
30635 isEnabled : function(){
30642 attribute : "qtip",
30652 // backwards compat
30653 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30655 * Ext JS Library 1.1.1
30656 * Copyright(c) 2006-2007, Ext JS, LLC.
30658 * Originally Released Under LGPL - original licence link has changed is not relivant.
30661 * <script type="text/javascript">
30666 * @class Roo.tree.TreePanel
30667 * @extends Roo.data.Tree
30669 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30670 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30671 * @cfg {Boolean} enableDD true to enable drag and drop
30672 * @cfg {Boolean} enableDrag true to enable just drag
30673 * @cfg {Boolean} enableDrop true to enable just drop
30674 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30675 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30676 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30677 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30678 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30679 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30680 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30681 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30682 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30683 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30684 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30685 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30686 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30687 * @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>
30688 * @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>
30691 * @param {String/HTMLElement/Element} el The container element
30692 * @param {Object} config
30694 Roo.tree.TreePanel = function(el, config){
30696 var loader = false;
30698 root = config.root;
30699 delete config.root;
30701 if (config.loader) {
30702 loader = config.loader;
30703 delete config.loader;
30706 Roo.apply(this, config);
30707 Roo.tree.TreePanel.superclass.constructor.call(this);
30708 this.el = Roo.get(el);
30709 this.el.addClass('x-tree');
30710 //console.log(root);
30712 this.setRootNode( Roo.factory(root, Roo.tree));
30715 this.loader = Roo.factory(loader, Roo.tree);
30718 * Read-only. The id of the container element becomes this TreePanel's id.
30720 this.id = this.el.id;
30723 * @event beforeload
30724 * Fires before a node is loaded, return false to cancel
30725 * @param {Node} node The node being loaded
30727 "beforeload" : true,
30730 * Fires when a node is loaded
30731 * @param {Node} node The node that was loaded
30735 * @event textchange
30736 * Fires when the text for a node is changed
30737 * @param {Node} node The node
30738 * @param {String} text The new text
30739 * @param {String} oldText The old text
30741 "textchange" : true,
30743 * @event beforeexpand
30744 * Fires before a node is expanded, return false to cancel.
30745 * @param {Node} node The node
30746 * @param {Boolean} deep
30747 * @param {Boolean} anim
30749 "beforeexpand" : true,
30751 * @event beforecollapse
30752 * Fires before a node is collapsed, return false to cancel.
30753 * @param {Node} node The node
30754 * @param {Boolean} deep
30755 * @param {Boolean} anim
30757 "beforecollapse" : true,
30760 * Fires when a node is expanded
30761 * @param {Node} node The node
30765 * @event disabledchange
30766 * Fires when the disabled status of a node changes
30767 * @param {Node} node The node
30768 * @param {Boolean} disabled
30770 "disabledchange" : true,
30773 * Fires when a node is collapsed
30774 * @param {Node} node The node
30778 * @event beforeclick
30779 * Fires before click processing on a node. Return false to cancel the default action.
30780 * @param {Node} node The node
30781 * @param {Roo.EventObject} e The event object
30783 "beforeclick":true,
30785 * @event checkchange
30786 * Fires when a node with a checkbox's checked property changes
30787 * @param {Node} this This node
30788 * @param {Boolean} checked
30790 "checkchange":true,
30793 * Fires when a node is clicked
30794 * @param {Node} node The node
30795 * @param {Roo.EventObject} e The event object
30800 * Fires when a node is double clicked
30801 * @param {Node} node The node
30802 * @param {Roo.EventObject} e The event object
30806 * @event contextmenu
30807 * Fires when a node is right clicked
30808 * @param {Node} node The node
30809 * @param {Roo.EventObject} e The event object
30811 "contextmenu":true,
30813 * @event beforechildrenrendered
30814 * Fires right before the child nodes for a node are rendered
30815 * @param {Node} node The node
30817 "beforechildrenrendered":true,
30820 * Fires when a node starts being dragged
30821 * @param {Roo.tree.TreePanel} this
30822 * @param {Roo.tree.TreeNode} node
30823 * @param {event} e The raw browser event
30825 "startdrag" : true,
30828 * Fires when a drag operation is complete
30829 * @param {Roo.tree.TreePanel} this
30830 * @param {Roo.tree.TreeNode} node
30831 * @param {event} e The raw browser event
30836 * Fires when a dragged node is dropped on a valid DD target
30837 * @param {Roo.tree.TreePanel} this
30838 * @param {Roo.tree.TreeNode} node
30839 * @param {DD} dd The dd it was dropped on
30840 * @param {event} e The raw browser event
30844 * @event beforenodedrop
30845 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30846 * passed to handlers has the following properties:<br />
30847 * <ul style="padding:5px;padding-left:16px;">
30848 * <li>tree - The TreePanel</li>
30849 * <li>target - The node being targeted for the drop</li>
30850 * <li>data - The drag data from the drag source</li>
30851 * <li>point - The point of the drop - append, above or below</li>
30852 * <li>source - The drag source</li>
30853 * <li>rawEvent - Raw mouse event</li>
30854 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30855 * to be inserted by setting them on this object.</li>
30856 * <li>cancel - Set this to true to cancel the drop.</li>
30858 * @param {Object} dropEvent
30860 "beforenodedrop" : true,
30863 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30864 * passed to handlers has the following properties:<br />
30865 * <ul style="padding:5px;padding-left:16px;">
30866 * <li>tree - The TreePanel</li>
30867 * <li>target - The node being targeted for the drop</li>
30868 * <li>data - The drag data from the drag source</li>
30869 * <li>point - The point of the drop - append, above or below</li>
30870 * <li>source - The drag source</li>
30871 * <li>rawEvent - Raw mouse event</li>
30872 * <li>dropNode - Dropped node(s).</li>
30874 * @param {Object} dropEvent
30878 * @event nodedragover
30879 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30880 * passed to handlers has the following properties:<br />
30881 * <ul style="padding:5px;padding-left:16px;">
30882 * <li>tree - The TreePanel</li>
30883 * <li>target - The node being targeted for the drop</li>
30884 * <li>data - The drag data from the drag source</li>
30885 * <li>point - The point of the drop - append, above or below</li>
30886 * <li>source - The drag source</li>
30887 * <li>rawEvent - Raw mouse event</li>
30888 * <li>dropNode - Drop node(s) provided by the source.</li>
30889 * <li>cancel - Set this to true to signal drop not allowed.</li>
30891 * @param {Object} dragOverEvent
30893 "nodedragover" : true
30896 if(this.singleExpand){
30897 this.on("beforeexpand", this.restrictExpand, this);
30900 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30901 rootVisible : true,
30902 animate: Roo.enableFx,
30905 hlDrop : Roo.enableFx,
30909 rendererTip: false,
30911 restrictExpand : function(node){
30912 var p = node.parentNode;
30914 if(p.expandedChild && p.expandedChild.parentNode == p){
30915 p.expandedChild.collapse();
30917 p.expandedChild = node;
30921 // private override
30922 setRootNode : function(node){
30923 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30924 if(!this.rootVisible){
30925 node.ui = new Roo.tree.RootTreeNodeUI(node);
30931 * Returns the container element for this TreePanel
30933 getEl : function(){
30938 * Returns the default TreeLoader for this TreePanel
30940 getLoader : function(){
30941 return this.loader;
30947 expandAll : function(){
30948 this.root.expand(true);
30952 * Collapse all nodes
30954 collapseAll : function(){
30955 this.root.collapse(true);
30959 * Returns the selection model used by this TreePanel
30961 getSelectionModel : function(){
30962 if(!this.selModel){
30963 this.selModel = new Roo.tree.DefaultSelectionModel();
30965 return this.selModel;
30969 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30970 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30971 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30974 getChecked : function(a, startNode){
30975 startNode = startNode || this.root;
30977 var f = function(){
30978 if(this.attributes.checked){
30979 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30982 startNode.cascade(f);
30987 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30988 * @param {String} path
30989 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30990 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30991 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30993 expandPath : function(path, attr, callback){
30994 attr = attr || "id";
30995 var keys = path.split(this.pathSeparator);
30996 var curNode = this.root;
30997 if(curNode.attributes[attr] != keys[1]){ // invalid root
30999 callback(false, null);
31004 var f = function(){
31005 if(++index == keys.length){
31007 callback(true, curNode);
31011 var c = curNode.findChild(attr, keys[index]);
31014 callback(false, curNode);
31019 c.expand(false, false, f);
31021 curNode.expand(false, false, f);
31025 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31026 * @param {String} path
31027 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31028 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31029 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31031 selectPath : function(path, attr, callback){
31032 attr = attr || "id";
31033 var keys = path.split(this.pathSeparator);
31034 var v = keys.pop();
31035 if(keys.length > 0){
31036 var f = function(success, node){
31037 if(success && node){
31038 var n = node.findChild(attr, v);
31044 }else if(callback){
31045 callback(false, n);
31049 callback(false, n);
31053 this.expandPath(keys.join(this.pathSeparator), attr, f);
31055 this.root.select();
31057 callback(true, this.root);
31062 getTreeEl : function(){
31067 * Trigger rendering of this TreePanel
31069 render : function(){
31070 if (this.innerCt) {
31071 return this; // stop it rendering more than once!!
31074 this.innerCt = this.el.createChild({tag:"ul",
31075 cls:"x-tree-root-ct " +
31076 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31078 if(this.containerScroll){
31079 Roo.dd.ScrollManager.register(this.el);
31081 if((this.enableDD || this.enableDrop) && !this.dropZone){
31083 * The dropZone used by this tree if drop is enabled
31084 * @type Roo.tree.TreeDropZone
31086 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31087 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31090 if((this.enableDD || this.enableDrag) && !this.dragZone){
31092 * The dragZone used by this tree if drag is enabled
31093 * @type Roo.tree.TreeDragZone
31095 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31096 ddGroup: this.ddGroup || "TreeDD",
31097 scroll: this.ddScroll
31100 this.getSelectionModel().init(this);
31102 console.log("ROOT not set in tree");
31105 this.root.render();
31106 if(!this.rootVisible){
31107 this.root.renderChildren();
31113 * Ext JS Library 1.1.1
31114 * Copyright(c) 2006-2007, Ext JS, LLC.
31116 * Originally Released Under LGPL - original licence link has changed is not relivant.
31119 * <script type="text/javascript">
31124 * @class Roo.tree.DefaultSelectionModel
31125 * @extends Roo.util.Observable
31126 * The default single selection for a TreePanel.
31128 Roo.tree.DefaultSelectionModel = function(){
31129 this.selNode = null;
31133 * @event selectionchange
31134 * Fires when the selected node changes
31135 * @param {DefaultSelectionModel} this
31136 * @param {TreeNode} node the new selection
31138 "selectionchange" : true,
31141 * @event beforeselect
31142 * Fires before the selected node changes, return false to cancel the change
31143 * @param {DefaultSelectionModel} this
31144 * @param {TreeNode} node the new selection
31145 * @param {TreeNode} node the old selection
31147 "beforeselect" : true
31151 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31152 init : function(tree){
31154 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31155 tree.on("click", this.onNodeClick, this);
31158 onNodeClick : function(node, e){
31159 if (e.ctrlKey && this.selNode == node) {
31160 this.unselect(node);
31168 * @param {TreeNode} node The node to select
31169 * @return {TreeNode} The selected node
31171 select : function(node){
31172 var last = this.selNode;
31173 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31175 last.ui.onSelectedChange(false);
31177 this.selNode = node;
31178 node.ui.onSelectedChange(true);
31179 this.fireEvent("selectionchange", this, node, last);
31186 * @param {TreeNode} node The node to unselect
31188 unselect : function(node){
31189 if(this.selNode == node){
31190 this.clearSelections();
31195 * Clear all selections
31197 clearSelections : function(){
31198 var n = this.selNode;
31200 n.ui.onSelectedChange(false);
31201 this.selNode = null;
31202 this.fireEvent("selectionchange", this, null);
31208 * Get the selected node
31209 * @return {TreeNode} The selected node
31211 getSelectedNode : function(){
31212 return this.selNode;
31216 * Returns true if the node is selected
31217 * @param {TreeNode} node The node to check
31218 * @return {Boolean}
31220 isSelected : function(node){
31221 return this.selNode == node;
31225 * Selects the node above the selected node in the tree, intelligently walking the nodes
31226 * @return TreeNode The new selection
31228 selectPrevious : function(){
31229 var s = this.selNode || this.lastSelNode;
31233 var ps = s.previousSibling;
31235 if(!ps.isExpanded() || ps.childNodes.length < 1){
31236 return this.select(ps);
31238 var lc = ps.lastChild;
31239 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31242 return this.select(lc);
31244 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31245 return this.select(s.parentNode);
31251 * Selects the node above the selected node in the tree, intelligently walking the nodes
31252 * @return TreeNode The new selection
31254 selectNext : function(){
31255 var s = this.selNode || this.lastSelNode;
31259 if(s.firstChild && s.isExpanded()){
31260 return this.select(s.firstChild);
31261 }else if(s.nextSibling){
31262 return this.select(s.nextSibling);
31263 }else if(s.parentNode){
31265 s.parentNode.bubble(function(){
31266 if(this.nextSibling){
31267 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31276 onKeyDown : function(e){
31277 var s = this.selNode || this.lastSelNode;
31278 // undesirable, but required
31283 var k = e.getKey();
31291 this.selectPrevious();
31294 e.preventDefault();
31295 if(s.hasChildNodes()){
31296 if(!s.isExpanded()){
31298 }else if(s.firstChild){
31299 this.select(s.firstChild, e);
31304 e.preventDefault();
31305 if(s.hasChildNodes() && s.isExpanded()){
31307 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31308 this.select(s.parentNode, e);
31316 * @class Roo.tree.MultiSelectionModel
31317 * @extends Roo.util.Observable
31318 * Multi selection for a TreePanel.
31320 Roo.tree.MultiSelectionModel = function(){
31321 this.selNodes = [];
31325 * @event selectionchange
31326 * Fires when the selected nodes change
31327 * @param {MultiSelectionModel} this
31328 * @param {Array} nodes Array of the selected nodes
31330 "selectionchange" : true
31334 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31335 init : function(tree){
31337 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31338 tree.on("click", this.onNodeClick, this);
31341 onNodeClick : function(node, e){
31342 this.select(node, e, e.ctrlKey);
31347 * @param {TreeNode} node The node to select
31348 * @param {EventObject} e (optional) An event associated with the selection
31349 * @param {Boolean} keepExisting True to retain existing selections
31350 * @return {TreeNode} The selected node
31352 select : function(node, e, keepExisting){
31353 if(keepExisting !== true){
31354 this.clearSelections(true);
31356 if(this.isSelected(node)){
31357 this.lastSelNode = node;
31360 this.selNodes.push(node);
31361 this.selMap[node.id] = node;
31362 this.lastSelNode = node;
31363 node.ui.onSelectedChange(true);
31364 this.fireEvent("selectionchange", this, this.selNodes);
31370 * @param {TreeNode} node The node to unselect
31372 unselect : function(node){
31373 if(this.selMap[node.id]){
31374 node.ui.onSelectedChange(false);
31375 var sn = this.selNodes;
31378 index = sn.indexOf(node);
31380 for(var i = 0, len = sn.length; i < len; i++){
31388 this.selNodes.splice(index, 1);
31390 delete this.selMap[node.id];
31391 this.fireEvent("selectionchange", this, this.selNodes);
31396 * Clear all selections
31398 clearSelections : function(suppressEvent){
31399 var sn = this.selNodes;
31401 for(var i = 0, len = sn.length; i < len; i++){
31402 sn[i].ui.onSelectedChange(false);
31404 this.selNodes = [];
31406 if(suppressEvent !== true){
31407 this.fireEvent("selectionchange", this, this.selNodes);
31413 * Returns true if the node is selected
31414 * @param {TreeNode} node The node to check
31415 * @return {Boolean}
31417 isSelected : function(node){
31418 return this.selMap[node.id] ? true : false;
31422 * Returns an array of the selected nodes
31425 getSelectedNodes : function(){
31426 return this.selNodes;
31429 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31431 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31433 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31436 * Ext JS Library 1.1.1
31437 * Copyright(c) 2006-2007, Ext JS, LLC.
31439 * Originally Released Under LGPL - original licence link has changed is not relivant.
31442 * <script type="text/javascript">
31446 * @class Roo.tree.TreeNode
31447 * @extends Roo.data.Node
31448 * @cfg {String} text The text for this node
31449 * @cfg {Boolean} expanded true to start the node expanded
31450 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31451 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31452 * @cfg {Boolean} disabled true to start the node disabled
31453 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31454 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31455 * @cfg {String} cls A css class to be added to the node
31456 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31457 * @cfg {String} href URL of the link used for the node (defaults to #)
31458 * @cfg {String} hrefTarget target frame for the link
31459 * @cfg {String} qtip An Ext QuickTip for the node
31460 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31461 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31462 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31463 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31464 * (defaults to undefined with no checkbox rendered)
31466 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31468 Roo.tree.TreeNode = function(attributes){
31469 attributes = attributes || {};
31470 if(typeof attributes == "string"){
31471 attributes = {text: attributes};
31473 this.childrenRendered = false;
31474 this.rendered = false;
31475 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31476 this.expanded = attributes.expanded === true;
31477 this.isTarget = attributes.isTarget !== false;
31478 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31479 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31482 * Read-only. The text for this node. To change it use setText().
31485 this.text = attributes.text;
31487 * True if this node is disabled.
31490 this.disabled = attributes.disabled === true;
31494 * @event textchange
31495 * Fires when the text for this node is changed
31496 * @param {Node} this This node
31497 * @param {String} text The new text
31498 * @param {String} oldText The old text
31500 "textchange" : true,
31502 * @event beforeexpand
31503 * Fires before this node is expanded, return false to cancel.
31504 * @param {Node} this This node
31505 * @param {Boolean} deep
31506 * @param {Boolean} anim
31508 "beforeexpand" : true,
31510 * @event beforecollapse
31511 * Fires before this node is collapsed, return false to cancel.
31512 * @param {Node} this This node
31513 * @param {Boolean} deep
31514 * @param {Boolean} anim
31516 "beforecollapse" : true,
31519 * Fires when this node is expanded
31520 * @param {Node} this This node
31524 * @event disabledchange
31525 * Fires when the disabled status of this node changes
31526 * @param {Node} this This node
31527 * @param {Boolean} disabled
31529 "disabledchange" : true,
31532 * Fires when this node is collapsed
31533 * @param {Node} this This node
31537 * @event beforeclick
31538 * Fires before click processing. Return false to cancel the default action.
31539 * @param {Node} this This node
31540 * @param {Roo.EventObject} e The event object
31542 "beforeclick":true,
31544 * @event checkchange
31545 * Fires when a node with a checkbox's checked property changes
31546 * @param {Node} this This node
31547 * @param {Boolean} checked
31549 "checkchange":true,
31552 * Fires when this node is clicked
31553 * @param {Node} this This node
31554 * @param {Roo.EventObject} e The event object
31559 * Fires when this node is double clicked
31560 * @param {Node} this This node
31561 * @param {Roo.EventObject} e The event object
31565 * @event contextmenu
31566 * Fires when this node is right clicked
31567 * @param {Node} this This node
31568 * @param {Roo.EventObject} e The event object
31570 "contextmenu":true,
31572 * @event beforechildrenrendered
31573 * Fires right before the child nodes for this node are rendered
31574 * @param {Node} this This node
31576 "beforechildrenrendered":true
31579 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31582 * Read-only. The UI for this node
31585 this.ui = new uiClass(this);
31587 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31588 preventHScroll: true,
31590 * Returns true if this node is expanded
31591 * @return {Boolean}
31593 isExpanded : function(){
31594 return this.expanded;
31598 * Returns the UI object for this node
31599 * @return {TreeNodeUI}
31601 getUI : function(){
31605 // private override
31606 setFirstChild : function(node){
31607 var of = this.firstChild;
31608 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31609 if(this.childrenRendered && of && node != of){
31610 of.renderIndent(true, true);
31613 this.renderIndent(true, true);
31617 // private override
31618 setLastChild : function(node){
31619 var ol = this.lastChild;
31620 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31621 if(this.childrenRendered && ol && node != ol){
31622 ol.renderIndent(true, true);
31625 this.renderIndent(true, true);
31629 // these methods are overridden to provide lazy rendering support
31630 // private override
31631 appendChild : function(){
31632 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31633 if(node && this.childrenRendered){
31636 this.ui.updateExpandIcon();
31640 // private override
31641 removeChild : function(node){
31642 this.ownerTree.getSelectionModel().unselect(node);
31643 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31644 // if it's been rendered remove dom node
31645 if(this.childrenRendered){
31648 if(this.childNodes.length < 1){
31649 this.collapse(false, false);
31651 this.ui.updateExpandIcon();
31653 if(!this.firstChild) {
31654 this.childrenRendered = false;
31659 // private override
31660 insertBefore : function(node, refNode){
31661 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31662 if(newNode && refNode && this.childrenRendered){
31665 this.ui.updateExpandIcon();
31670 * Sets the text for this node
31671 * @param {String} text
31673 setText : function(text){
31674 var oldText = this.text;
31676 this.attributes.text = text;
31677 if(this.rendered){ // event without subscribing
31678 this.ui.onTextChange(this, text, oldText);
31680 this.fireEvent("textchange", this, text, oldText);
31684 * Triggers selection of this node
31686 select : function(){
31687 this.getOwnerTree().getSelectionModel().select(this);
31691 * Triggers deselection of this node
31693 unselect : function(){
31694 this.getOwnerTree().getSelectionModel().unselect(this);
31698 * Returns true if this node is selected
31699 * @return {Boolean}
31701 isSelected : function(){
31702 return this.getOwnerTree().getSelectionModel().isSelected(this);
31706 * Expand this node.
31707 * @param {Boolean} deep (optional) True to expand all children as well
31708 * @param {Boolean} anim (optional) false to cancel the default animation
31709 * @param {Function} callback (optional) A callback to be called when
31710 * expanding this node completes (does not wait for deep expand to complete).
31711 * Called with 1 parameter, this node.
31713 expand : function(deep, anim, callback){
31714 if(!this.expanded){
31715 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31718 if(!this.childrenRendered){
31719 this.renderChildren();
31721 this.expanded = true;
31722 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31723 this.ui.animExpand(function(){
31724 this.fireEvent("expand", this);
31725 if(typeof callback == "function"){
31729 this.expandChildNodes(true);
31731 }.createDelegate(this));
31735 this.fireEvent("expand", this);
31736 if(typeof callback == "function"){
31741 if(typeof callback == "function"){
31746 this.expandChildNodes(true);
31750 isHiddenRoot : function(){
31751 return this.isRoot && !this.getOwnerTree().rootVisible;
31755 * Collapse this node.
31756 * @param {Boolean} deep (optional) True to collapse all children as well
31757 * @param {Boolean} anim (optional) false to cancel the default animation
31759 collapse : function(deep, anim){
31760 if(this.expanded && !this.isHiddenRoot()){
31761 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31764 this.expanded = false;
31765 if((this.getOwnerTree().animate && anim !== false) || anim){
31766 this.ui.animCollapse(function(){
31767 this.fireEvent("collapse", this);
31769 this.collapseChildNodes(true);
31771 }.createDelegate(this));
31774 this.ui.collapse();
31775 this.fireEvent("collapse", this);
31779 var cs = this.childNodes;
31780 for(var i = 0, len = cs.length; i < len; i++) {
31781 cs[i].collapse(true, false);
31787 delayedExpand : function(delay){
31788 if(!this.expandProcId){
31789 this.expandProcId = this.expand.defer(delay, this);
31794 cancelExpand : function(){
31795 if(this.expandProcId){
31796 clearTimeout(this.expandProcId);
31798 this.expandProcId = false;
31802 * Toggles expanded/collapsed state of the node
31804 toggle : function(){
31813 * Ensures all parent nodes are expanded
31815 ensureVisible : function(callback){
31816 var tree = this.getOwnerTree();
31817 tree.expandPath(this.parentNode.getPath(), false, function(){
31818 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31819 Roo.callback(callback);
31820 }.createDelegate(this));
31824 * Expand all child nodes
31825 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31827 expandChildNodes : function(deep){
31828 var cs = this.childNodes;
31829 for(var i = 0, len = cs.length; i < len; i++) {
31830 cs[i].expand(deep);
31835 * Collapse all child nodes
31836 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31838 collapseChildNodes : function(deep){
31839 var cs = this.childNodes;
31840 for(var i = 0, len = cs.length; i < len; i++) {
31841 cs[i].collapse(deep);
31846 * Disables this node
31848 disable : function(){
31849 this.disabled = true;
31851 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31852 this.ui.onDisableChange(this, true);
31854 this.fireEvent("disabledchange", this, true);
31858 * Enables this node
31860 enable : function(){
31861 this.disabled = false;
31862 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31863 this.ui.onDisableChange(this, false);
31865 this.fireEvent("disabledchange", this, false);
31869 renderChildren : function(suppressEvent){
31870 if(suppressEvent !== false){
31871 this.fireEvent("beforechildrenrendered", this);
31873 var cs = this.childNodes;
31874 for(var i = 0, len = cs.length; i < len; i++){
31875 cs[i].render(true);
31877 this.childrenRendered = true;
31881 sort : function(fn, scope){
31882 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31883 if(this.childrenRendered){
31884 var cs = this.childNodes;
31885 for(var i = 0, len = cs.length; i < len; i++){
31886 cs[i].render(true);
31892 render : function(bulkRender){
31893 this.ui.render(bulkRender);
31894 if(!this.rendered){
31895 this.rendered = true;
31897 this.expanded = false;
31898 this.expand(false, false);
31904 renderIndent : function(deep, refresh){
31906 this.ui.childIndent = null;
31908 this.ui.renderIndent();
31909 if(deep === true && this.childrenRendered){
31910 var cs = this.childNodes;
31911 for(var i = 0, len = cs.length; i < len; i++){
31912 cs[i].renderIndent(true, refresh);
31918 * Ext JS Library 1.1.1
31919 * Copyright(c) 2006-2007, Ext JS, LLC.
31921 * Originally Released Under LGPL - original licence link has changed is not relivant.
31924 * <script type="text/javascript">
31928 * @class Roo.tree.AsyncTreeNode
31929 * @extends Roo.tree.TreeNode
31930 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31932 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31934 Roo.tree.AsyncTreeNode = function(config){
31935 this.loaded = false;
31936 this.loading = false;
31937 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31939 * @event beforeload
31940 * Fires before this node is loaded, return false to cancel
31941 * @param {Node} this This node
31943 this.addEvents({'beforeload':true, 'load': true});
31946 * Fires when this node is loaded
31947 * @param {Node} this This node
31950 * The loader used by this node (defaults to using the tree's defined loader)
31955 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31956 expand : function(deep, anim, callback){
31957 if(this.loading){ // if an async load is already running, waiting til it's done
31959 var f = function(){
31960 if(!this.loading){ // done loading
31961 clearInterval(timer);
31962 this.expand(deep, anim, callback);
31964 }.createDelegate(this);
31965 timer = setInterval(f, 200);
31969 if(this.fireEvent("beforeload", this) === false){
31972 this.loading = true;
31973 this.ui.beforeLoad(this);
31974 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31976 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31980 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31984 * Returns true if this node is currently loading
31985 * @return {Boolean}
31987 isLoading : function(){
31988 return this.loading;
31991 loadComplete : function(deep, anim, callback){
31992 this.loading = false;
31993 this.loaded = true;
31994 this.ui.afterLoad(this);
31995 this.fireEvent("load", this);
31996 this.expand(deep, anim, callback);
32000 * Returns true if this node has been loaded
32001 * @return {Boolean}
32003 isLoaded : function(){
32004 return this.loaded;
32007 hasChildNodes : function(){
32008 if(!this.isLeaf() && !this.loaded){
32011 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32016 * Trigger a reload for this node
32017 * @param {Function} callback
32019 reload : function(callback){
32020 this.collapse(false, false);
32021 while(this.firstChild){
32022 this.removeChild(this.firstChild);
32024 this.childrenRendered = false;
32025 this.loaded = false;
32026 if(this.isHiddenRoot()){
32027 this.expanded = false;
32029 this.expand(false, false, callback);
32033 * Ext JS Library 1.1.1
32034 * Copyright(c) 2006-2007, Ext JS, LLC.
32036 * Originally Released Under LGPL - original licence link has changed is not relivant.
32039 * <script type="text/javascript">
32043 * @class Roo.tree.TreeNodeUI
32045 * @param {Object} node The node to render
32046 * The TreeNode UI implementation is separate from the
32047 * tree implementation. Unless you are customizing the tree UI,
32048 * you should never have to use this directly.
32050 Roo.tree.TreeNodeUI = function(node){
32052 this.rendered = false;
32053 this.animating = false;
32054 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32057 Roo.tree.TreeNodeUI.prototype = {
32058 removeChild : function(node){
32060 this.ctNode.removeChild(node.ui.getEl());
32064 beforeLoad : function(){
32065 this.addClass("x-tree-node-loading");
32068 afterLoad : function(){
32069 this.removeClass("x-tree-node-loading");
32072 onTextChange : function(node, text, oldText){
32074 this.textNode.innerHTML = text;
32078 onDisableChange : function(node, state){
32079 this.disabled = state;
32081 this.addClass("x-tree-node-disabled");
32083 this.removeClass("x-tree-node-disabled");
32087 onSelectedChange : function(state){
32090 this.addClass("x-tree-selected");
32093 this.removeClass("x-tree-selected");
32097 onMove : function(tree, node, oldParent, newParent, index, refNode){
32098 this.childIndent = null;
32100 var targetNode = newParent.ui.getContainer();
32101 if(!targetNode){//target not rendered
32102 this.holder = document.createElement("div");
32103 this.holder.appendChild(this.wrap);
32106 var insertBefore = refNode ? refNode.ui.getEl() : null;
32108 targetNode.insertBefore(this.wrap, insertBefore);
32110 targetNode.appendChild(this.wrap);
32112 this.node.renderIndent(true);
32116 addClass : function(cls){
32118 Roo.fly(this.elNode).addClass(cls);
32122 removeClass : function(cls){
32124 Roo.fly(this.elNode).removeClass(cls);
32128 remove : function(){
32130 this.holder = document.createElement("div");
32131 this.holder.appendChild(this.wrap);
32135 fireEvent : function(){
32136 return this.node.fireEvent.apply(this.node, arguments);
32139 initEvents : function(){
32140 this.node.on("move", this.onMove, this);
32141 var E = Roo.EventManager;
32142 var a = this.anchor;
32144 var el = Roo.fly(a, '_treeui');
32146 if(Roo.isOpera){ // opera render bug ignores the CSS
32147 el.setStyle("text-decoration", "none");
32150 el.on("click", this.onClick, this);
32151 el.on("dblclick", this.onDblClick, this);
32154 Roo.EventManager.on(this.checkbox,
32155 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32158 el.on("contextmenu", this.onContextMenu, this);
32160 var icon = Roo.fly(this.iconNode);
32161 icon.on("click", this.onClick, this);
32162 icon.on("dblclick", this.onDblClick, this);
32163 icon.on("contextmenu", this.onContextMenu, this);
32164 E.on(this.ecNode, "click", this.ecClick, this, true);
32166 if(this.node.disabled){
32167 this.addClass("x-tree-node-disabled");
32169 if(this.node.hidden){
32170 this.addClass("x-tree-node-disabled");
32172 var ot = this.node.getOwnerTree();
32173 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32174 if(dd && (!this.node.isRoot || ot.rootVisible)){
32175 Roo.dd.Registry.register(this.elNode, {
32177 handles: this.getDDHandles(),
32183 getDDHandles : function(){
32184 return [this.iconNode, this.textNode];
32189 this.wrap.style.display = "none";
32195 this.wrap.style.display = "";
32199 onContextMenu : function(e){
32200 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32201 e.preventDefault();
32203 this.fireEvent("contextmenu", this.node, e);
32207 onClick : function(e){
32212 if(this.fireEvent("beforeclick", this.node, e) !== false){
32213 if(!this.disabled && this.node.attributes.href){
32214 this.fireEvent("click", this.node, e);
32217 e.preventDefault();
32222 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32223 this.node.toggle();
32226 this.fireEvent("click", this.node, e);
32232 onDblClick : function(e){
32233 e.preventDefault();
32238 this.toggleCheck();
32240 if(!this.animating && this.node.hasChildNodes()){
32241 this.node.toggle();
32243 this.fireEvent("dblclick", this.node, e);
32246 onCheckChange : function(){
32247 var checked = this.checkbox.checked;
32248 this.node.attributes.checked = checked;
32249 this.fireEvent('checkchange', this.node, checked);
32252 ecClick : function(e){
32253 if(!this.animating && this.node.hasChildNodes()){
32254 this.node.toggle();
32258 startDrop : function(){
32259 this.dropping = true;
32262 // delayed drop so the click event doesn't get fired on a drop
32263 endDrop : function(){
32264 setTimeout(function(){
32265 this.dropping = false;
32266 }.createDelegate(this), 50);
32269 expand : function(){
32270 this.updateExpandIcon();
32271 this.ctNode.style.display = "";
32274 focus : function(){
32275 if(!this.node.preventHScroll){
32276 try{this.anchor.focus();
32278 }else if(!Roo.isIE){
32280 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32281 var l = noscroll.scrollLeft;
32282 this.anchor.focus();
32283 noscroll.scrollLeft = l;
32288 toggleCheck : function(value){
32289 var cb = this.checkbox;
32291 cb.checked = (value === undefined ? !cb.checked : value);
32297 this.anchor.blur();
32301 animExpand : function(callback){
32302 var ct = Roo.get(this.ctNode);
32304 if(!this.node.hasChildNodes()){
32305 this.updateExpandIcon();
32306 this.ctNode.style.display = "";
32307 Roo.callback(callback);
32310 this.animating = true;
32311 this.updateExpandIcon();
32314 callback : function(){
32315 this.animating = false;
32316 Roo.callback(callback);
32319 duration: this.node.ownerTree.duration || .25
32323 highlight : function(){
32324 var tree = this.node.getOwnerTree();
32325 Roo.fly(this.wrap).highlight(
32326 tree.hlColor || "C3DAF9",
32327 {endColor: tree.hlBaseColor}
32331 collapse : function(){
32332 this.updateExpandIcon();
32333 this.ctNode.style.display = "none";
32336 animCollapse : function(callback){
32337 var ct = Roo.get(this.ctNode);
32338 ct.enableDisplayMode('block');
32341 this.animating = true;
32342 this.updateExpandIcon();
32345 callback : function(){
32346 this.animating = false;
32347 Roo.callback(callback);
32350 duration: this.node.ownerTree.duration || .25
32354 getContainer : function(){
32355 return this.ctNode;
32358 getEl : function(){
32362 appendDDGhost : function(ghostNode){
32363 ghostNode.appendChild(this.elNode.cloneNode(true));
32366 getDDRepairXY : function(){
32367 return Roo.lib.Dom.getXY(this.iconNode);
32370 onRender : function(){
32374 render : function(bulkRender){
32375 var n = this.node, a = n.attributes;
32376 var targetNode = n.parentNode ?
32377 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32379 if(!this.rendered){
32380 this.rendered = true;
32382 this.renderElements(n, a, targetNode, bulkRender);
32385 if(this.textNode.setAttributeNS){
32386 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32388 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32391 this.textNode.setAttribute("ext:qtip", a.qtip);
32393 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32396 }else if(a.qtipCfg){
32397 a.qtipCfg.target = Roo.id(this.textNode);
32398 Roo.QuickTips.register(a.qtipCfg);
32401 if(!this.node.expanded){
32402 this.updateExpandIcon();
32405 if(bulkRender === true) {
32406 targetNode.appendChild(this.wrap);
32411 renderElements : function(n, a, targetNode, bulkRender){
32412 // add some indent caching, this helps performance when rendering a large tree
32413 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32414 var t = n.getOwnerTree();
32415 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32416 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32417 var cb = typeof a.checked == 'boolean';
32418 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32419 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32420 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32421 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32422 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32423 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32424 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32425 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32426 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32427 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32430 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32431 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32432 n.nextSibling.ui.getEl(), buf.join(""));
32434 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32437 this.elNode = this.wrap.childNodes[0];
32438 this.ctNode = this.wrap.childNodes[1];
32439 var cs = this.elNode.childNodes;
32440 this.indentNode = cs[0];
32441 this.ecNode = cs[1];
32442 this.iconNode = cs[2];
32445 this.checkbox = cs[3];
32448 this.anchor = cs[index];
32449 this.textNode = cs[index].firstChild;
32452 getAnchor : function(){
32453 return this.anchor;
32456 getTextEl : function(){
32457 return this.textNode;
32460 getIconEl : function(){
32461 return this.iconNode;
32464 isChecked : function(){
32465 return this.checkbox ? this.checkbox.checked : false;
32468 updateExpandIcon : function(){
32470 var n = this.node, c1, c2;
32471 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32472 var hasChild = n.hasChildNodes();
32476 c1 = "x-tree-node-collapsed";
32477 c2 = "x-tree-node-expanded";
32480 c1 = "x-tree-node-expanded";
32481 c2 = "x-tree-node-collapsed";
32484 this.removeClass("x-tree-node-leaf");
32485 this.wasLeaf = false;
32487 if(this.c1 != c1 || this.c2 != c2){
32488 Roo.fly(this.elNode).replaceClass(c1, c2);
32489 this.c1 = c1; this.c2 = c2;
32493 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32496 this.wasLeaf = true;
32499 var ecc = "x-tree-ec-icon "+cls;
32500 if(this.ecc != ecc){
32501 this.ecNode.className = ecc;
32507 getChildIndent : function(){
32508 if(!this.childIndent){
32512 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32514 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32516 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32521 this.childIndent = buf.join("");
32523 return this.childIndent;
32526 renderIndent : function(){
32529 var p = this.node.parentNode;
32531 indent = p.ui.getChildIndent();
32533 if(this.indentMarkup != indent){ // don't rerender if not required
32534 this.indentNode.innerHTML = indent;
32535 this.indentMarkup = indent;
32537 this.updateExpandIcon();
32542 Roo.tree.RootTreeNodeUI = function(){
32543 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32545 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32546 render : function(){
32547 if(!this.rendered){
32548 var targetNode = this.node.ownerTree.innerCt.dom;
32549 this.node.expanded = true;
32550 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32551 this.wrap = this.ctNode = targetNode.firstChild;
32554 collapse : function(){
32556 expand : function(){
32560 * Ext JS Library 1.1.1
32561 * Copyright(c) 2006-2007, Ext JS, LLC.
32563 * Originally Released Under LGPL - original licence link has changed is not relivant.
32566 * <script type="text/javascript">
32569 * @class Roo.tree.TreeLoader
32570 * @extends Roo.util.Observable
32571 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32572 * nodes from a specified URL. The response must be a javascript Array definition
32573 * who's elements are node definition objects. eg:
32575 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32576 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32579 * A server request is sent, and child nodes are loaded only when a node is expanded.
32580 * The loading node's id is passed to the server under the parameter name "node" to
32581 * enable the server to produce the correct child nodes.
32583 * To pass extra parameters, an event handler may be attached to the "beforeload"
32584 * event, and the parameters specified in the TreeLoader's baseParams property:
32586 myTreeLoader.on("beforeload", function(treeLoader, node) {
32587 this.baseParams.category = node.attributes.category;
32590 * This would pass an HTTP parameter called "category" to the server containing
32591 * the value of the Node's "category" attribute.
32593 * Creates a new Treeloader.
32594 * @param {Object} config A config object containing config properties.
32596 Roo.tree.TreeLoader = function(config){
32597 this.baseParams = {};
32598 this.requestMethod = "POST";
32599 Roo.apply(this, config);
32604 * @event beforeload
32605 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32606 * @param {Object} This TreeLoader object.
32607 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32608 * @param {Object} callback The callback function specified in the {@link #load} call.
32613 * Fires when the node has been successfuly loaded.
32614 * @param {Object} This TreeLoader object.
32615 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32616 * @param {Object} response The response object containing the data from the server.
32620 * @event loadexception
32621 * Fires if the network request failed.
32622 * @param {Object} This TreeLoader object.
32623 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32624 * @param {Object} response The response object containing the data from the server.
32626 loadexception : true,
32629 * Fires before a node is created, enabling you to return custom Node types
32630 * @param {Object} This TreeLoader object.
32631 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32636 Roo.tree.TreeLoader.superclass.constructor.call(this);
32639 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32641 * @cfg {String} dataUrl The URL from which to request a Json string which
32642 * specifies an array of node definition object representing the child nodes
32646 * @cfg {Object} baseParams (optional) An object containing properties which
32647 * specify HTTP parameters to be passed to each request for child nodes.
32650 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32651 * created by this loader. If the attributes sent by the server have an attribute in this object,
32652 * they take priority.
32655 * @cfg {Object} uiProviders (optional) An object containing properties which
32657 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32658 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32659 * <i>uiProvider</i> attribute of a returned child node is a string rather
32660 * than a reference to a TreeNodeUI implementation, this that string value
32661 * is used as a property name in the uiProviders object. You can define the provider named
32662 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32667 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32668 * child nodes before loading.
32670 clearOnLoad : true,
32673 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32674 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32675 * Grid query { data : [ .....] }
32680 * @cfg {String} queryParam (optional)
32681 * Name of the query as it will be passed on the querystring (defaults to 'node')
32682 * eg. the request will be ?node=[id]
32689 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32690 * This is called automatically when a node is expanded, but may be used to reload
32691 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32692 * @param {Roo.tree.TreeNode} node
32693 * @param {Function} callback
32695 load : function(node, callback){
32696 if(this.clearOnLoad){
32697 while(node.firstChild){
32698 node.removeChild(node.firstChild);
32701 if(node.attributes.children){ // preloaded json children
32702 var cs = node.attributes.children;
32703 for(var i = 0, len = cs.length; i < len; i++){
32704 node.appendChild(this.createNode(cs[i]));
32706 if(typeof callback == "function"){
32709 }else if(this.dataUrl){
32710 this.requestData(node, callback);
32714 getParams: function(node){
32715 var buf = [], bp = this.baseParams;
32716 for(var key in bp){
32717 if(typeof bp[key] != "function"){
32718 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32721 var n = this.queryParam === false ? 'node' : this.queryParam;
32722 buf.push(n + "=", encodeURIComponent(node.id));
32723 return buf.join("");
32726 requestData : function(node, callback){
32727 if(this.fireEvent("beforeload", this, node, callback) !== false){
32728 this.transId = Roo.Ajax.request({
32729 method:this.requestMethod,
32730 url: this.dataUrl||this.url,
32731 success: this.handleResponse,
32732 failure: this.handleFailure,
32734 argument: {callback: callback, node: node},
32735 params: this.getParams(node)
32738 // if the load is cancelled, make sure we notify
32739 // the node that we are done
32740 if(typeof callback == "function"){
32746 isLoading : function(){
32747 return this.transId ? true : false;
32750 abort : function(){
32751 if(this.isLoading()){
32752 Roo.Ajax.abort(this.transId);
32757 createNode : function(attr){
32758 // apply baseAttrs, nice idea Corey!
32759 if(this.baseAttrs){
32760 Roo.applyIf(attr, this.baseAttrs);
32762 if(this.applyLoader !== false){
32763 attr.loader = this;
32765 // uiProvider = depreciated..
32767 if(typeof(attr.uiProvider) == 'string'){
32768 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32769 /** eval:var:attr */ eval(attr.uiProvider);
32771 if(typeof(this.uiProviders['default']) != 'undefined') {
32772 attr.uiProvider = this.uiProviders['default'];
32775 this.fireEvent('create', this, attr);
32777 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32779 new Roo.tree.TreeNode(attr) :
32780 new Roo.tree.AsyncTreeNode(attr));
32783 processResponse : function(response, node, callback){
32784 var json = response.responseText;
32787 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32788 if (this.root !== false) {
32792 for(var i = 0, len = o.length; i < len; i++){
32793 var n = this.createNode(o[i]);
32795 node.appendChild(n);
32798 if(typeof callback == "function"){
32799 callback(this, node);
32802 this.handleFailure(response);
32806 handleResponse : function(response){
32807 this.transId = false;
32808 var a = response.argument;
32809 this.processResponse(response, a.node, a.callback);
32810 this.fireEvent("load", this, a.node, response);
32813 handleFailure : function(response){
32814 this.transId = false;
32815 var a = response.argument;
32816 this.fireEvent("loadexception", this, a.node, response);
32817 if(typeof a.callback == "function"){
32818 a.callback(this, a.node);
32823 * Ext JS Library 1.1.1
32824 * Copyright(c) 2006-2007, Ext JS, LLC.
32826 * Originally Released Under LGPL - original licence link has changed is not relivant.
32829 * <script type="text/javascript">
32833 * @class Roo.tree.TreeFilter
32834 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32835 * @param {TreePanel} tree
32836 * @param {Object} config (optional)
32838 Roo.tree.TreeFilter = function(tree, config){
32840 this.filtered = {};
32841 Roo.apply(this, config);
32844 Roo.tree.TreeFilter.prototype = {
32851 * Filter the data by a specific attribute.
32852 * @param {String/RegExp} value Either string that the attribute value
32853 * should start with or a RegExp to test against the attribute
32854 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32855 * @param {TreeNode} startNode (optional) The node to start the filter at.
32857 filter : function(value, attr, startNode){
32858 attr = attr || "text";
32860 if(typeof value == "string"){
32861 var vlen = value.length;
32862 // auto clear empty filter
32863 if(vlen == 0 && this.clearBlank){
32867 value = value.toLowerCase();
32869 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32871 }else if(value.exec){ // regex?
32873 return value.test(n.attributes[attr]);
32876 throw 'Illegal filter type, must be string or regex';
32878 this.filterBy(f, null, startNode);
32882 * Filter by a function. The passed function will be called with each
32883 * node in the tree (or from the startNode). If the function returns true, the node is kept
32884 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32885 * @param {Function} fn The filter function
32886 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32888 filterBy : function(fn, scope, startNode){
32889 startNode = startNode || this.tree.root;
32890 if(this.autoClear){
32893 var af = this.filtered, rv = this.reverse;
32894 var f = function(n){
32895 if(n == startNode){
32901 var m = fn.call(scope || n, n);
32909 startNode.cascade(f);
32912 if(typeof id != "function"){
32914 if(n && n.parentNode){
32915 n.parentNode.removeChild(n);
32923 * Clears the current filter. Note: with the "remove" option
32924 * set a filter cannot be cleared.
32926 clear : function(){
32928 var af = this.filtered;
32930 if(typeof id != "function"){
32937 this.filtered = {};
32942 * Ext JS Library 1.1.1
32943 * Copyright(c) 2006-2007, Ext JS, LLC.
32945 * Originally Released Under LGPL - original licence link has changed is not relivant.
32948 * <script type="text/javascript">
32953 * @class Roo.tree.TreeSorter
32954 * Provides sorting of nodes in a TreePanel
32956 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32957 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32958 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32959 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32960 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32961 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32963 * @param {TreePanel} tree
32964 * @param {Object} config
32966 Roo.tree.TreeSorter = function(tree, config){
32967 Roo.apply(this, config);
32968 tree.on("beforechildrenrendered", this.doSort, this);
32969 tree.on("append", this.updateSort, this);
32970 tree.on("insert", this.updateSort, this);
32972 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32973 var p = this.property || "text";
32974 var sortType = this.sortType;
32975 var fs = this.folderSort;
32976 var cs = this.caseSensitive === true;
32977 var leafAttr = this.leafAttr || 'leaf';
32979 this.sortFn = function(n1, n2){
32981 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32984 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32988 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32989 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32991 return dsc ? +1 : -1;
32993 return dsc ? -1 : +1;
33000 Roo.tree.TreeSorter.prototype = {
33001 doSort : function(node){
33002 node.sort(this.sortFn);
33005 compareNodes : function(n1, n2){
33006 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33009 updateSort : function(tree, node){
33010 if(node.childrenRendered){
33011 this.doSort.defer(1, this, [node]);
33016 * Ext JS Library 1.1.1
33017 * Copyright(c) 2006-2007, Ext JS, LLC.
33019 * Originally Released Under LGPL - original licence link has changed is not relivant.
33022 * <script type="text/javascript">
33025 if(Roo.dd.DropZone){
33027 Roo.tree.TreeDropZone = function(tree, config){
33028 this.allowParentInsert = false;
33029 this.allowContainerDrop = false;
33030 this.appendOnly = false;
33031 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33033 this.lastInsertClass = "x-tree-no-status";
33034 this.dragOverData = {};
33037 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33038 ddGroup : "TreeDD",
33040 expandDelay : 1000,
33042 expandNode : function(node){
33043 if(node.hasChildNodes() && !node.isExpanded()){
33044 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33048 queueExpand : function(node){
33049 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33052 cancelExpand : function(){
33053 if(this.expandProcId){
33054 clearTimeout(this.expandProcId);
33055 this.expandProcId = false;
33059 isValidDropPoint : function(n, pt, dd, e, data){
33060 if(!n || !data){ return false; }
33061 var targetNode = n.node;
33062 var dropNode = data.node;
33063 // default drop rules
33064 if(!(targetNode && targetNode.isTarget && pt)){
33067 if(pt == "append" && targetNode.allowChildren === false){
33070 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33073 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33076 // reuse the object
33077 var overEvent = this.dragOverData;
33078 overEvent.tree = this.tree;
33079 overEvent.target = targetNode;
33080 overEvent.data = data;
33081 overEvent.point = pt;
33082 overEvent.source = dd;
33083 overEvent.rawEvent = e;
33084 overEvent.dropNode = dropNode;
33085 overEvent.cancel = false;
33086 var result = this.tree.fireEvent("nodedragover", overEvent);
33087 return overEvent.cancel === false && result !== false;
33090 getDropPoint : function(e, n, dd){
33093 return tn.allowChildren !== false ? "append" : false; // always append for root
33095 var dragEl = n.ddel;
33096 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33097 var y = Roo.lib.Event.getPageY(e);
33098 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33100 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33101 var noAppend = tn.allowChildren === false;
33102 if(this.appendOnly || tn.parentNode.allowChildren === false){
33103 return noAppend ? false : "append";
33105 var noBelow = false;
33106 if(!this.allowParentInsert){
33107 noBelow = tn.hasChildNodes() && tn.isExpanded();
33109 var q = (b - t) / (noAppend ? 2 : 3);
33110 if(y >= t && y < (t + q)){
33112 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33119 onNodeEnter : function(n, dd, e, data){
33120 this.cancelExpand();
33123 onNodeOver : function(n, dd, e, data){
33124 var pt = this.getDropPoint(e, n, dd);
33127 // auto node expand check
33128 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33129 this.queueExpand(node);
33130 }else if(pt != "append"){
33131 this.cancelExpand();
33134 // set the insert point style on the target node
33135 var returnCls = this.dropNotAllowed;
33136 if(this.isValidDropPoint(n, pt, dd, e, data)){
33141 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33142 cls = "x-tree-drag-insert-above";
33143 }else if(pt == "below"){
33144 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33145 cls = "x-tree-drag-insert-below";
33147 returnCls = "x-tree-drop-ok-append";
33148 cls = "x-tree-drag-append";
33150 if(this.lastInsertClass != cls){
33151 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33152 this.lastInsertClass = cls;
33159 onNodeOut : function(n, dd, e, data){
33160 this.cancelExpand();
33161 this.removeDropIndicators(n);
33164 onNodeDrop : function(n, dd, e, data){
33165 var point = this.getDropPoint(e, n, dd);
33166 var targetNode = n.node;
33167 targetNode.ui.startDrop();
33168 if(!this.isValidDropPoint(n, point, dd, e, data)){
33169 targetNode.ui.endDrop();
33172 // first try to find the drop node
33173 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33176 target: targetNode,
33181 dropNode: dropNode,
33184 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33185 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33186 targetNode.ui.endDrop();
33189 // allow target changing
33190 targetNode = dropEvent.target;
33191 if(point == "append" && !targetNode.isExpanded()){
33192 targetNode.expand(false, null, function(){
33193 this.completeDrop(dropEvent);
33194 }.createDelegate(this));
33196 this.completeDrop(dropEvent);
33201 completeDrop : function(de){
33202 var ns = de.dropNode, p = de.point, t = de.target;
33203 if(!(ns instanceof Array)){
33207 for(var i = 0, len = ns.length; i < len; i++){
33210 t.parentNode.insertBefore(n, t);
33211 }else if(p == "below"){
33212 t.parentNode.insertBefore(n, t.nextSibling);
33218 if(this.tree.hlDrop){
33222 this.tree.fireEvent("nodedrop", de);
33225 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33226 if(this.tree.hlDrop){
33227 dropNode.ui.focus();
33228 dropNode.ui.highlight();
33230 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33233 getTree : function(){
33237 removeDropIndicators : function(n){
33240 Roo.fly(el).removeClass([
33241 "x-tree-drag-insert-above",
33242 "x-tree-drag-insert-below",
33243 "x-tree-drag-append"]);
33244 this.lastInsertClass = "_noclass";
33248 beforeDragDrop : function(target, e, id){
33249 this.cancelExpand();
33253 afterRepair : function(data){
33254 if(data && Roo.enableFx){
33255 data.node.ui.highlight();
33264 * Ext JS Library 1.1.1
33265 * Copyright(c) 2006-2007, Ext JS, LLC.
33267 * Originally Released Under LGPL - original licence link has changed is not relivant.
33270 * <script type="text/javascript">
33274 if(Roo.dd.DragZone){
33275 Roo.tree.TreeDragZone = function(tree, config){
33276 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33280 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33281 ddGroup : "TreeDD",
33283 onBeforeDrag : function(data, e){
33285 return n && n.draggable && !n.disabled;
33288 onInitDrag : function(e){
33289 var data = this.dragData;
33290 this.tree.getSelectionModel().select(data.node);
33291 this.proxy.update("");
33292 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33293 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33296 getRepairXY : function(e, data){
33297 return data.node.ui.getDDRepairXY();
33300 onEndDrag : function(data, e){
33301 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33304 onValidDrop : function(dd, e, id){
33305 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33309 beforeInvalidDrop : function(e, id){
33310 // this scrolls the original position back into view
33311 var sm = this.tree.getSelectionModel();
33312 sm.clearSelections();
33313 sm.select(this.dragData.node);
33318 * Ext JS Library 1.1.1
33319 * Copyright(c) 2006-2007, Ext JS, LLC.
33321 * Originally Released Under LGPL - original licence link has changed is not relivant.
33324 * <script type="text/javascript">
33327 * @class Roo.tree.TreeEditor
33328 * @extends Roo.Editor
33329 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33330 * as the editor field.
33332 * @param {TreePanel} tree
33333 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33335 Roo.tree.TreeEditor = function(tree, config){
33336 config = config || {};
33337 var field = config.events ? config : new Roo.form.TextField(config);
33338 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33342 tree.on('beforeclick', this.beforeNodeClick, this);
33343 tree.getTreeEl().on('mousedown', this.hide, this);
33344 this.on('complete', this.updateNode, this);
33345 this.on('beforestartedit', this.fitToTree, this);
33346 this.on('startedit', this.bindScroll, this, {delay:10});
33347 this.on('specialkey', this.onSpecialKey, this);
33350 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33352 * @cfg {String} alignment
33353 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33359 * @cfg {Boolean} hideEl
33360 * True to hide the bound element while the editor is displayed (defaults to false)
33364 * @cfg {String} cls
33365 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33367 cls: "x-small-editor x-tree-editor",
33369 * @cfg {Boolean} shim
33370 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33376 * @cfg {Number} maxWidth
33377 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33378 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33379 * scroll and client offsets into account prior to each edit.
33386 fitToTree : function(ed, el){
33387 var td = this.tree.getTreeEl().dom, nd = el.dom;
33388 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33389 td.scrollLeft = nd.offsetLeft;
33393 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33394 this.setSize(w, '');
33398 triggerEdit : function(node){
33399 this.completeEdit();
33400 this.editNode = node;
33401 this.startEdit(node.ui.textNode, node.text);
33405 bindScroll : function(){
33406 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33410 beforeNodeClick : function(node, e){
33411 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33412 this.lastClick = new Date();
33413 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33415 this.triggerEdit(node);
33421 updateNode : function(ed, value){
33422 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33423 this.editNode.setText(value);
33427 onHide : function(){
33428 Roo.tree.TreeEditor.superclass.onHide.call(this);
33430 this.editNode.ui.focus();
33435 onSpecialKey : function(field, e){
33436 var k = e.getKey();
33440 }else if(k == e.ENTER && !e.hasModifier()){
33442 this.completeEdit();
33445 });//<Script type="text/javascript">
33448 * Ext JS Library 1.1.1
33449 * Copyright(c) 2006-2007, Ext JS, LLC.
33451 * Originally Released Under LGPL - original licence link has changed is not relivant.
33454 * <script type="text/javascript">
33458 * Not documented??? - probably should be...
33461 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33462 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33464 renderElements : function(n, a, targetNode, bulkRender){
33465 //consel.log("renderElements?");
33466 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33468 var t = n.getOwnerTree();
33469 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33471 var cols = t.columns;
33472 var bw = t.borderWidth;
33474 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33475 var cb = typeof a.checked == "boolean";
33476 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33477 var colcls = 'x-t-' + tid + '-c0';
33479 '<li class="x-tree-node">',
33482 '<div class="x-tree-node-el ', a.cls,'">',
33484 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33487 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33488 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33489 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33490 (a.icon ? ' x-tree-node-inline-icon' : ''),
33491 (a.iconCls ? ' '+a.iconCls : ''),
33492 '" unselectable="on" />',
33493 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33494 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33496 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33497 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33498 '<span unselectable="on" qtip="' + tx + '">',
33502 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33503 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33505 for(var i = 1, len = cols.length; i < len; i++){
33507 colcls = 'x-t-' + tid + '-c' +i;
33508 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33509 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33510 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33516 '<div class="x-clear"></div></div>',
33517 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33520 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33521 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33522 n.nextSibling.ui.getEl(), buf.join(""));
33524 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33526 var el = this.wrap.firstChild;
33528 this.elNode = el.firstChild;
33529 this.ranchor = el.childNodes[1];
33530 this.ctNode = this.wrap.childNodes[1];
33531 var cs = el.firstChild.childNodes;
33532 this.indentNode = cs[0];
33533 this.ecNode = cs[1];
33534 this.iconNode = cs[2];
33537 this.checkbox = cs[3];
33540 this.anchor = cs[index];
33542 this.textNode = cs[index].firstChild;
33544 //el.on("click", this.onClick, this);
33545 //el.on("dblclick", this.onDblClick, this);
33548 // console.log(this);
33550 initEvents : function(){
33551 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33554 var a = this.ranchor;
33556 var el = Roo.get(a);
33558 if(Roo.isOpera){ // opera render bug ignores the CSS
33559 el.setStyle("text-decoration", "none");
33562 el.on("click", this.onClick, this);
33563 el.on("dblclick", this.onDblClick, this);
33564 el.on("contextmenu", this.onContextMenu, this);
33568 /*onSelectedChange : function(state){
33571 this.addClass("x-tree-selected");
33574 this.removeClass("x-tree-selected");
33577 addClass : function(cls){
33579 Roo.fly(this.elRow).addClass(cls);
33585 removeClass : function(cls){
33587 Roo.fly(this.elRow).removeClass(cls);
33593 });//<Script type="text/javascript">
33597 * Ext JS Library 1.1.1
33598 * Copyright(c) 2006-2007, Ext JS, LLC.
33600 * Originally Released Under LGPL - original licence link has changed is not relivant.
33603 * <script type="text/javascript">
33608 * @class Roo.tree.ColumnTree
33609 * @extends Roo.data.TreePanel
33610 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33611 * @cfg {int} borderWidth compined right/left border allowance
33613 * @param {String/HTMLElement/Element} el The container element
33614 * @param {Object} config
33616 Roo.tree.ColumnTree = function(el, config)
33618 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33622 * Fire this event on a container when it resizes
33623 * @param {int} w Width
33624 * @param {int} h Height
33628 this.on('resize', this.onResize, this);
33631 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33635 borderWidth: Roo.isBorderBox ? 0 : 2,
33638 render : function(){
33639 // add the header.....
33641 Roo.tree.ColumnTree.superclass.render.apply(this);
33643 this.el.addClass('x-column-tree');
33645 this.headers = this.el.createChild(
33646 {cls:'x-tree-headers'},this.innerCt.dom);
33648 var cols = this.columns, c;
33649 var totalWidth = 0;
33651 var len = cols.length;
33652 for(var i = 0; i < len; i++){
33654 totalWidth += c.width;
33655 this.headEls.push(this.headers.createChild({
33656 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33658 cls:'x-tree-hd-text',
33661 style:'width:'+(c.width-this.borderWidth)+'px;'
33664 this.headers.createChild({cls:'x-clear'});
33665 // prevent floats from wrapping when clipped
33666 this.headers.setWidth(totalWidth);
33667 //this.innerCt.setWidth(totalWidth);
33668 this.innerCt.setStyle({ overflow: 'auto' });
33669 this.onResize(this.width, this.height);
33673 onResize : function(w,h)
33678 this.innerCt.setWidth(this.width);
33679 this.innerCt.setHeight(this.height-20);
33682 var cols = this.columns, c;
33683 var totalWidth = 0;
33685 var len = cols.length;
33686 for(var i = 0; i < len; i++){
33688 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33689 // it's the expander..
33690 expEl = this.headEls[i];
33693 totalWidth += c.width;
33697 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33699 this.headers.setWidth(w-20);
33708 * Ext JS Library 1.1.1
33709 * Copyright(c) 2006-2007, Ext JS, LLC.
33711 * Originally Released Under LGPL - original licence link has changed is not relivant.
33714 * <script type="text/javascript">
33718 * @class Roo.menu.Menu
33719 * @extends Roo.util.Observable
33720 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33721 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33723 * Creates a new Menu
33724 * @param {Object} config Configuration options
33726 Roo.menu.Menu = function(config){
33727 Roo.apply(this, config);
33728 this.id = this.id || Roo.id();
33731 * @event beforeshow
33732 * Fires before this menu is displayed
33733 * @param {Roo.menu.Menu} this
33737 * @event beforehide
33738 * Fires before this menu is hidden
33739 * @param {Roo.menu.Menu} this
33744 * Fires after this menu is displayed
33745 * @param {Roo.menu.Menu} this
33750 * Fires after this menu is hidden
33751 * @param {Roo.menu.Menu} this
33756 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33757 * @param {Roo.menu.Menu} this
33758 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33759 * @param {Roo.EventObject} e
33764 * Fires when the mouse is hovering over this menu
33765 * @param {Roo.menu.Menu} this
33766 * @param {Roo.EventObject} e
33767 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33772 * Fires when the mouse exits this menu
33773 * @param {Roo.menu.Menu} this
33774 * @param {Roo.EventObject} e
33775 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33780 * Fires when a menu item contained in this menu is clicked
33781 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33782 * @param {Roo.EventObject} e
33786 if (this.registerMenu) {
33787 Roo.menu.MenuMgr.register(this);
33790 var mis = this.items;
33791 this.items = new Roo.util.MixedCollection();
33793 this.add.apply(this, mis);
33797 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33799 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33803 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33804 * for bottom-right shadow (defaults to "sides")
33808 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33809 * this menu (defaults to "tl-tr?")
33811 subMenuAlign : "tl-tr?",
33813 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33814 * relative to its element of origin (defaults to "tl-bl?")
33816 defaultAlign : "tl-bl?",
33818 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33820 allowOtherMenus : false,
33822 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33824 registerMenu : true,
33829 render : function(){
33833 var el = this.el = new Roo.Layer({
33835 shadow:this.shadow,
33837 parentEl: this.parentEl || document.body,
33841 this.keyNav = new Roo.menu.MenuNav(this);
33844 el.addClass("x-menu-plain");
33847 el.addClass(this.cls);
33849 // generic focus element
33850 this.focusEl = el.createChild({
33851 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33853 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33854 ul.on("click", this.onClick, this);
33855 ul.on("mouseover", this.onMouseOver, this);
33856 ul.on("mouseout", this.onMouseOut, this);
33857 this.items.each(function(item){
33858 var li = document.createElement("li");
33859 li.className = "x-menu-list-item";
33860 ul.dom.appendChild(li);
33861 item.render(li, this);
33868 autoWidth : function(){
33869 var el = this.el, ul = this.ul;
33873 var w = this.width;
33876 }else if(Roo.isIE){
33877 el.setWidth(this.minWidth);
33878 var t = el.dom.offsetWidth; // force recalc
33879 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33884 delayAutoWidth : function(){
33887 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33889 this.awTask.delay(20);
33894 findTargetItem : function(e){
33895 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33896 if(t && t.menuItemId){
33897 return this.items.get(t.menuItemId);
33902 onClick : function(e){
33904 if(t = this.findTargetItem(e)){
33906 this.fireEvent("click", this, t, e);
33911 setActiveItem : function(item, autoExpand){
33912 if(item != this.activeItem){
33913 if(this.activeItem){
33914 this.activeItem.deactivate();
33916 this.activeItem = item;
33917 item.activate(autoExpand);
33918 }else if(autoExpand){
33924 tryActivate : function(start, step){
33925 var items = this.items;
33926 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33927 var item = items.get(i);
33928 if(!item.disabled && item.canActivate){
33929 this.setActiveItem(item, false);
33937 onMouseOver : function(e){
33939 if(t = this.findTargetItem(e)){
33940 if(t.canActivate && !t.disabled){
33941 this.setActiveItem(t, true);
33944 this.fireEvent("mouseover", this, e, t);
33948 onMouseOut : function(e){
33950 if(t = this.findTargetItem(e)){
33951 if(t == this.activeItem && t.shouldDeactivate(e)){
33952 this.activeItem.deactivate();
33953 delete this.activeItem;
33956 this.fireEvent("mouseout", this, e, t);
33960 * Read-only. Returns true if the menu is currently displayed, else false.
33963 isVisible : function(){
33964 return this.el && !this.hidden;
33968 * Displays this menu relative to another element
33969 * @param {String/HTMLElement/Roo.Element} element The element to align to
33970 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33971 * the element (defaults to this.defaultAlign)
33972 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33974 show : function(el, pos, parentMenu){
33975 this.parentMenu = parentMenu;
33979 this.fireEvent("beforeshow", this);
33980 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33984 * Displays this menu at a specific xy position
33985 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33986 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33988 showAt : function(xy, parentMenu, /* private: */_e){
33989 this.parentMenu = parentMenu;
33994 this.fireEvent("beforeshow", this);
33995 xy = this.el.adjustForConstraints(xy);
33999 this.hidden = false;
34001 this.fireEvent("show", this);
34004 focus : function(){
34006 this.doFocus.defer(50, this);
34010 doFocus : function(){
34012 this.focusEl.focus();
34017 * Hides this menu and optionally all parent menus
34018 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34020 hide : function(deep){
34021 if(this.el && this.isVisible()){
34022 this.fireEvent("beforehide", this);
34023 if(this.activeItem){
34024 this.activeItem.deactivate();
34025 this.activeItem = null;
34028 this.hidden = true;
34029 this.fireEvent("hide", this);
34031 if(deep === true && this.parentMenu){
34032 this.parentMenu.hide(true);
34037 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34038 * Any of the following are valid:
34040 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34041 * <li>An HTMLElement object which will be converted to a menu item</li>
34042 * <li>A menu item config object that will be created as a new menu item</li>
34043 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34044 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34049 var menu = new Roo.menu.Menu();
34051 // Create a menu item to add by reference
34052 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34054 // Add a bunch of items at once using different methods.
34055 // Only the last item added will be returned.
34056 var item = menu.add(
34057 menuItem, // add existing item by ref
34058 'Dynamic Item', // new TextItem
34059 '-', // new separator
34060 { text: 'Config Item' } // new item by config
34063 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34064 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34067 var a = arguments, l = a.length, item;
34068 for(var i = 0; i < l; i++){
34070 if ((typeof(el) == "object") && el.xtype && el.xns) {
34071 el = Roo.factory(el, Roo.menu);
34074 if(el.render){ // some kind of Item
34075 item = this.addItem(el);
34076 }else if(typeof el == "string"){ // string
34077 if(el == "separator" || el == "-"){
34078 item = this.addSeparator();
34080 item = this.addText(el);
34082 }else if(el.tagName || el.el){ // element
34083 item = this.addElement(el);
34084 }else if(typeof el == "object"){ // must be menu item config?
34085 item = this.addMenuItem(el);
34092 * Returns this menu's underlying {@link Roo.Element} object
34093 * @return {Roo.Element} The element
34095 getEl : function(){
34103 * Adds a separator bar to the menu
34104 * @return {Roo.menu.Item} The menu item that was added
34106 addSeparator : function(){
34107 return this.addItem(new Roo.menu.Separator());
34111 * Adds an {@link Roo.Element} object to the menu
34112 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34113 * @return {Roo.menu.Item} The menu item that was added
34115 addElement : function(el){
34116 return this.addItem(new Roo.menu.BaseItem(el));
34120 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34121 * @param {Roo.menu.Item} item The menu item to add
34122 * @return {Roo.menu.Item} The menu item that was added
34124 addItem : function(item){
34125 this.items.add(item);
34127 var li = document.createElement("li");
34128 li.className = "x-menu-list-item";
34129 this.ul.dom.appendChild(li);
34130 item.render(li, this);
34131 this.delayAutoWidth();
34137 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34138 * @param {Object} config A MenuItem config object
34139 * @return {Roo.menu.Item} The menu item that was added
34141 addMenuItem : function(config){
34142 if(!(config instanceof Roo.menu.Item)){
34143 if(typeof config.checked == "boolean"){ // must be check menu item config?
34144 config = new Roo.menu.CheckItem(config);
34146 config = new Roo.menu.Item(config);
34149 return this.addItem(config);
34153 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34154 * @param {String} text The text to display in the menu item
34155 * @return {Roo.menu.Item} The menu item that was added
34157 addText : function(text){
34158 return this.addItem(new Roo.menu.TextItem({ text : text }));
34162 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34163 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34164 * @param {Roo.menu.Item} item The menu item to add
34165 * @return {Roo.menu.Item} The menu item that was added
34167 insert : function(index, item){
34168 this.items.insert(index, item);
34170 var li = document.createElement("li");
34171 li.className = "x-menu-list-item";
34172 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34173 item.render(li, this);
34174 this.delayAutoWidth();
34180 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34181 * @param {Roo.menu.Item} item The menu item to remove
34183 remove : function(item){
34184 this.items.removeKey(item.id);
34189 * Removes and destroys all items in the menu
34191 removeAll : function(){
34193 while(f = this.items.first()){
34199 // MenuNav is a private utility class used internally by the Menu
34200 Roo.menu.MenuNav = function(menu){
34201 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34202 this.scope = this.menu = menu;
34205 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34206 doRelay : function(e, h){
34207 var k = e.getKey();
34208 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34209 this.menu.tryActivate(0, 1);
34212 return h.call(this.scope || this, e, this.menu);
34215 up : function(e, m){
34216 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34217 m.tryActivate(m.items.length-1, -1);
34221 down : function(e, m){
34222 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34223 m.tryActivate(0, 1);
34227 right : function(e, m){
34229 m.activeItem.expandMenu(true);
34233 left : function(e, m){
34235 if(m.parentMenu && m.parentMenu.activeItem){
34236 m.parentMenu.activeItem.activate();
34240 enter : function(e, m){
34242 e.stopPropagation();
34243 m.activeItem.onClick(e);
34244 m.fireEvent("click", this, m.activeItem);
34250 * Ext JS Library 1.1.1
34251 * Copyright(c) 2006-2007, Ext JS, LLC.
34253 * Originally Released Under LGPL - original licence link has changed is not relivant.
34256 * <script type="text/javascript">
34260 * @class Roo.menu.MenuMgr
34261 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34264 Roo.menu.MenuMgr = function(){
34265 var menus, active, groups = {}, attached = false, lastShow = new Date();
34267 // private - called when first menu is created
34270 active = new Roo.util.MixedCollection();
34271 Roo.get(document).addKeyListener(27, function(){
34272 if(active.length > 0){
34279 function hideAll(){
34280 if(active && active.length > 0){
34281 var c = active.clone();
34282 c.each(function(m){
34289 function onHide(m){
34291 if(active.length < 1){
34292 Roo.get(document).un("mousedown", onMouseDown);
34298 function onShow(m){
34299 var last = active.last();
34300 lastShow = new Date();
34303 Roo.get(document).on("mousedown", onMouseDown);
34307 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34308 m.parentMenu.activeChild = m;
34309 }else if(last && last.isVisible()){
34310 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34315 function onBeforeHide(m){
34317 m.activeChild.hide();
34319 if(m.autoHideTimer){
34320 clearTimeout(m.autoHideTimer);
34321 delete m.autoHideTimer;
34326 function onBeforeShow(m){
34327 var pm = m.parentMenu;
34328 if(!pm && !m.allowOtherMenus){
34330 }else if(pm && pm.activeChild && active != m){
34331 pm.activeChild.hide();
34336 function onMouseDown(e){
34337 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34343 function onBeforeCheck(mi, state){
34345 var g = groups[mi.group];
34346 for(var i = 0, l = g.length; i < l; i++){
34348 g[i].setChecked(false);
34357 * Hides all menus that are currently visible
34359 hideAll : function(){
34364 register : function(menu){
34368 menus[menu.id] = menu;
34369 menu.on("beforehide", onBeforeHide);
34370 menu.on("hide", onHide);
34371 menu.on("beforeshow", onBeforeShow);
34372 menu.on("show", onShow);
34373 var g = menu.group;
34374 if(g && menu.events["checkchange"]){
34378 groups[g].push(menu);
34379 menu.on("checkchange", onCheck);
34384 * Returns a {@link Roo.menu.Menu} object
34385 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34386 * be used to generate and return a new Menu instance.
34388 get : function(menu){
34389 if(typeof menu == "string"){ // menu id
34390 return menus[menu];
34391 }else if(menu.events){ // menu instance
34393 }else if(typeof menu.length == 'number'){ // array of menu items?
34394 return new Roo.menu.Menu({items:menu});
34395 }else{ // otherwise, must be a config
34396 return new Roo.menu.Menu(menu);
34401 unregister : function(menu){
34402 delete menus[menu.id];
34403 menu.un("beforehide", onBeforeHide);
34404 menu.un("hide", onHide);
34405 menu.un("beforeshow", onBeforeShow);
34406 menu.un("show", onShow);
34407 var g = menu.group;
34408 if(g && menu.events["checkchange"]){
34409 groups[g].remove(menu);
34410 menu.un("checkchange", onCheck);
34415 registerCheckable : function(menuItem){
34416 var g = menuItem.group;
34421 groups[g].push(menuItem);
34422 menuItem.on("beforecheckchange", onBeforeCheck);
34427 unregisterCheckable : function(menuItem){
34428 var g = menuItem.group;
34430 groups[g].remove(menuItem);
34431 menuItem.un("beforecheckchange", onBeforeCheck);
34437 * Ext JS Library 1.1.1
34438 * Copyright(c) 2006-2007, Ext JS, LLC.
34440 * Originally Released Under LGPL - original licence link has changed is not relivant.
34443 * <script type="text/javascript">
34448 * @class Roo.menu.BaseItem
34449 * @extends Roo.Component
34450 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34451 * management and base configuration options shared by all menu components.
34453 * Creates a new BaseItem
34454 * @param {Object} config Configuration options
34456 Roo.menu.BaseItem = function(config){
34457 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34462 * Fires when this item is clicked
34463 * @param {Roo.menu.BaseItem} this
34464 * @param {Roo.EventObject} e
34469 * Fires when this item is activated
34470 * @param {Roo.menu.BaseItem} this
34474 * @event deactivate
34475 * Fires when this item is deactivated
34476 * @param {Roo.menu.BaseItem} this
34482 this.on("click", this.handler, this.scope, true);
34486 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34488 * @cfg {Function} handler
34489 * A function that will handle the click event of this menu item (defaults to undefined)
34492 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34494 canActivate : false,
34496 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34498 activeClass : "x-menu-item-active",
34500 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34502 hideOnClick : true,
34504 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34509 ctype: "Roo.menu.BaseItem",
34512 actionMode : "container",
34515 render : function(container, parentMenu){
34516 this.parentMenu = parentMenu;
34517 Roo.menu.BaseItem.superclass.render.call(this, container);
34518 this.container.menuItemId = this.id;
34522 onRender : function(container, position){
34523 this.el = Roo.get(this.el);
34524 container.dom.appendChild(this.el.dom);
34528 onClick : function(e){
34529 if(!this.disabled && this.fireEvent("click", this, e) !== false
34530 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34531 this.handleClick(e);
34538 activate : function(){
34542 var li = this.container;
34543 li.addClass(this.activeClass);
34544 this.region = li.getRegion().adjust(2, 2, -2, -2);
34545 this.fireEvent("activate", this);
34550 deactivate : function(){
34551 this.container.removeClass(this.activeClass);
34552 this.fireEvent("deactivate", this);
34556 shouldDeactivate : function(e){
34557 return !this.region || !this.region.contains(e.getPoint());
34561 handleClick : function(e){
34562 if(this.hideOnClick){
34563 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34568 expandMenu : function(autoActivate){
34573 hideMenu : function(){
34578 * Ext JS Library 1.1.1
34579 * Copyright(c) 2006-2007, Ext JS, LLC.
34581 * Originally Released Under LGPL - original licence link has changed is not relivant.
34584 * <script type="text/javascript">
34588 * @class Roo.menu.Adapter
34589 * @extends Roo.menu.BaseItem
34590 * 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.
34591 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34593 * Creates a new Adapter
34594 * @param {Object} config Configuration options
34596 Roo.menu.Adapter = function(component, config){
34597 Roo.menu.Adapter.superclass.constructor.call(this, config);
34598 this.component = component;
34600 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34602 canActivate : true,
34605 onRender : function(container, position){
34606 this.component.render(container);
34607 this.el = this.component.getEl();
34611 activate : function(){
34615 this.component.focus();
34616 this.fireEvent("activate", this);
34621 deactivate : function(){
34622 this.fireEvent("deactivate", this);
34626 disable : function(){
34627 this.component.disable();
34628 Roo.menu.Adapter.superclass.disable.call(this);
34632 enable : function(){
34633 this.component.enable();
34634 Roo.menu.Adapter.superclass.enable.call(this);
34638 * Ext JS Library 1.1.1
34639 * Copyright(c) 2006-2007, Ext JS, LLC.
34641 * Originally Released Under LGPL - original licence link has changed is not relivant.
34644 * <script type="text/javascript">
34648 * @class Roo.menu.TextItem
34649 * @extends Roo.menu.BaseItem
34650 * Adds a static text string to a menu, usually used as either a heading or group separator.
34651 * Note: old style constructor with text is still supported.
34654 * Creates a new TextItem
34655 * @param {Object} cfg Configuration
34657 Roo.menu.TextItem = function(cfg){
34658 if (typeof(cfg) == 'string') {
34661 Roo.apply(this,cfg);
34664 Roo.menu.TextItem.superclass.constructor.call(this);
34667 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34669 * @cfg {Boolean} text Text to show on item.
34674 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34676 hideOnClick : false,
34678 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34680 itemCls : "x-menu-text",
34683 onRender : function(){
34684 var s = document.createElement("span");
34685 s.className = this.itemCls;
34686 s.innerHTML = this.text;
34688 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34692 * Ext JS Library 1.1.1
34693 * Copyright(c) 2006-2007, Ext JS, LLC.
34695 * Originally Released Under LGPL - original licence link has changed is not relivant.
34698 * <script type="text/javascript">
34702 * @class Roo.menu.Separator
34703 * @extends Roo.menu.BaseItem
34704 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34705 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34707 * @param {Object} config Configuration options
34709 Roo.menu.Separator = function(config){
34710 Roo.menu.Separator.superclass.constructor.call(this, config);
34713 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34715 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34717 itemCls : "x-menu-sep",
34719 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34721 hideOnClick : false,
34724 onRender : function(li){
34725 var s = document.createElement("span");
34726 s.className = this.itemCls;
34727 s.innerHTML = " ";
34729 li.addClass("x-menu-sep-li");
34730 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34734 * Ext JS Library 1.1.1
34735 * Copyright(c) 2006-2007, Ext JS, LLC.
34737 * Originally Released Under LGPL - original licence link has changed is not relivant.
34740 * <script type="text/javascript">
34743 * @class Roo.menu.Item
34744 * @extends Roo.menu.BaseItem
34745 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34746 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34747 * activation and click handling.
34749 * Creates a new Item
34750 * @param {Object} config Configuration options
34752 Roo.menu.Item = function(config){
34753 Roo.menu.Item.superclass.constructor.call(this, config);
34755 this.menu = Roo.menu.MenuMgr.get(this.menu);
34758 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34761 * @cfg {String} text
34762 * The text to show on the menu item.
34766 * @cfg {String} HTML to render in menu
34767 * The text to show on the menu item (HTML version).
34771 * @cfg {String} icon
34772 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34776 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34778 itemCls : "x-menu-item",
34780 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34782 canActivate : true,
34784 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34787 // doc'd in BaseItem
34791 ctype: "Roo.menu.Item",
34794 onRender : function(container, position){
34795 var el = document.createElement("a");
34796 el.hideFocus = true;
34797 el.unselectable = "on";
34798 el.href = this.href || "#";
34799 if(this.hrefTarget){
34800 el.target = this.hrefTarget;
34802 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34804 var html = this.html.length ? this.html : String.format('{0}',this.text);
34806 el.innerHTML = String.format(
34807 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34808 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34810 Roo.menu.Item.superclass.onRender.call(this, container, position);
34814 * Sets the text to display in this menu item
34815 * @param {String} text The text to display
34816 * @param {Boolean} isHTML true to indicate text is pure html.
34818 setText : function(text, isHTML){
34826 var html = this.html.length ? this.html : String.format('{0}',this.text);
34828 this.el.update(String.format(
34829 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34830 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34831 this.parentMenu.autoWidth();
34836 handleClick : function(e){
34837 if(!this.href){ // if no link defined, stop the event automatically
34840 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34844 activate : function(autoExpand){
34845 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34855 shouldDeactivate : function(e){
34856 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34857 if(this.menu && this.menu.isVisible()){
34858 return !this.menu.getEl().getRegion().contains(e.getPoint());
34866 deactivate : function(){
34867 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34872 expandMenu : function(autoActivate){
34873 if(!this.disabled && this.menu){
34874 clearTimeout(this.hideTimer);
34875 delete this.hideTimer;
34876 if(!this.menu.isVisible() && !this.showTimer){
34877 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34878 }else if (this.menu.isVisible() && autoActivate){
34879 this.menu.tryActivate(0, 1);
34885 deferExpand : function(autoActivate){
34886 delete this.showTimer;
34887 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34889 this.menu.tryActivate(0, 1);
34894 hideMenu : function(){
34895 clearTimeout(this.showTimer);
34896 delete this.showTimer;
34897 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34898 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34903 deferHide : function(){
34904 delete this.hideTimer;
34909 * Ext JS Library 1.1.1
34910 * Copyright(c) 2006-2007, Ext JS, LLC.
34912 * Originally Released Under LGPL - original licence link has changed is not relivant.
34915 * <script type="text/javascript">
34919 * @class Roo.menu.CheckItem
34920 * @extends Roo.menu.Item
34921 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34923 * Creates a new CheckItem
34924 * @param {Object} config Configuration options
34926 Roo.menu.CheckItem = function(config){
34927 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34930 * @event beforecheckchange
34931 * Fires before the checked value is set, providing an opportunity to cancel if needed
34932 * @param {Roo.menu.CheckItem} this
34933 * @param {Boolean} checked The new checked value that will be set
34935 "beforecheckchange" : true,
34937 * @event checkchange
34938 * Fires after the checked value has been set
34939 * @param {Roo.menu.CheckItem} this
34940 * @param {Boolean} checked The checked value that was set
34942 "checkchange" : true
34944 if(this.checkHandler){
34945 this.on('checkchange', this.checkHandler, this.scope);
34948 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34950 * @cfg {String} group
34951 * All check items with the same group name will automatically be grouped into a single-select
34952 * radio button group (defaults to '')
34955 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34957 itemCls : "x-menu-item x-menu-check-item",
34959 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34961 groupClass : "x-menu-group-item",
34964 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34965 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34966 * initialized with checked = true will be rendered as checked.
34971 ctype: "Roo.menu.CheckItem",
34974 onRender : function(c){
34975 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34977 this.el.addClass(this.groupClass);
34979 Roo.menu.MenuMgr.registerCheckable(this);
34981 this.checked = false;
34982 this.setChecked(true, true);
34987 destroy : function(){
34989 Roo.menu.MenuMgr.unregisterCheckable(this);
34991 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34995 * Set the checked state of this item
34996 * @param {Boolean} checked The new checked value
34997 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
34999 setChecked : function(state, suppressEvent){
35000 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35001 if(this.container){
35002 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35004 this.checked = state;
35005 if(suppressEvent !== true){
35006 this.fireEvent("checkchange", this, state);
35012 handleClick : function(e){
35013 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35014 this.setChecked(!this.checked);
35016 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35020 * Ext JS Library 1.1.1
35021 * Copyright(c) 2006-2007, Ext JS, LLC.
35023 * Originally Released Under LGPL - original licence link has changed is not relivant.
35026 * <script type="text/javascript">
35030 * @class Roo.menu.DateItem
35031 * @extends Roo.menu.Adapter
35032 * A menu item that wraps the {@link Roo.DatPicker} component.
35034 * Creates a new DateItem
35035 * @param {Object} config Configuration options
35037 Roo.menu.DateItem = function(config){
35038 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35039 /** The Roo.DatePicker object @type Roo.DatePicker */
35040 this.picker = this.component;
35041 this.addEvents({select: true});
35043 this.picker.on("render", function(picker){
35044 picker.getEl().swallowEvent("click");
35045 picker.container.addClass("x-menu-date-item");
35048 this.picker.on("select", this.onSelect, this);
35051 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35053 onSelect : function(picker, date){
35054 this.fireEvent("select", this, date, picker);
35055 Roo.menu.DateItem.superclass.handleClick.call(this);
35059 * Ext JS Library 1.1.1
35060 * Copyright(c) 2006-2007, Ext JS, LLC.
35062 * Originally Released Under LGPL - original licence link has changed is not relivant.
35065 * <script type="text/javascript">
35069 * @class Roo.menu.ColorItem
35070 * @extends Roo.menu.Adapter
35071 * A menu item that wraps the {@link Roo.ColorPalette} component.
35073 * Creates a new ColorItem
35074 * @param {Object} config Configuration options
35076 Roo.menu.ColorItem = function(config){
35077 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35078 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35079 this.palette = this.component;
35080 this.relayEvents(this.palette, ["select"]);
35081 if(this.selectHandler){
35082 this.on('select', this.selectHandler, this.scope);
35085 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35087 * Ext JS Library 1.1.1
35088 * Copyright(c) 2006-2007, Ext JS, LLC.
35090 * Originally Released Under LGPL - original licence link has changed is not relivant.
35093 * <script type="text/javascript">
35098 * @class Roo.menu.DateMenu
35099 * @extends Roo.menu.Menu
35100 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35102 * Creates a new DateMenu
35103 * @param {Object} config Configuration options
35105 Roo.menu.DateMenu = function(config){
35106 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35108 var di = new Roo.menu.DateItem(config);
35111 * The {@link Roo.DatePicker} instance for this DateMenu
35114 this.picker = di.picker;
35117 * @param {DatePicker} picker
35118 * @param {Date} date
35120 this.relayEvents(di, ["select"]);
35122 this.on('beforeshow', function(){
35124 this.picker.hideMonthPicker(true);
35128 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35132 * Ext JS Library 1.1.1
35133 * Copyright(c) 2006-2007, Ext JS, LLC.
35135 * Originally Released Under LGPL - original licence link has changed is not relivant.
35138 * <script type="text/javascript">
35143 * @class Roo.menu.ColorMenu
35144 * @extends Roo.menu.Menu
35145 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35147 * Creates a new ColorMenu
35148 * @param {Object} config Configuration options
35150 Roo.menu.ColorMenu = function(config){
35151 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35153 var ci = new Roo.menu.ColorItem(config);
35156 * The {@link Roo.ColorPalette} instance for this ColorMenu
35157 * @type ColorPalette
35159 this.palette = ci.palette;
35162 * @param {ColorPalette} palette
35163 * @param {String} color
35165 this.relayEvents(ci, ["select"]);
35167 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35169 * Ext JS Library 1.1.1
35170 * Copyright(c) 2006-2007, Ext JS, LLC.
35172 * Originally Released Under LGPL - original licence link has changed is not relivant.
35175 * <script type="text/javascript">
35179 * @class Roo.form.Field
35180 * @extends Roo.BoxComponent
35181 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35183 * Creates a new Field
35184 * @param {Object} config Configuration options
35186 Roo.form.Field = function(config){
35187 Roo.form.Field.superclass.constructor.call(this, config);
35190 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35192 * @cfg {String} fieldLabel Label to use when rendering a form.
35195 * @cfg {String} qtip Mouse over tip
35199 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35201 invalidClass : "x-form-invalid",
35203 * @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")
35205 invalidText : "The value in this field is invalid",
35207 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35209 focusClass : "x-form-focus",
35211 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35212 automatic validation (defaults to "keyup").
35214 validationEvent : "keyup",
35216 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35218 validateOnBlur : true,
35220 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35222 validationDelay : 250,
35224 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35225 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35227 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35229 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35231 fieldClass : "x-form-field",
35233 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35236 ----------- ----------------------------------------------------------------------
35237 qtip Display a quick tip when the user hovers over the field
35238 title Display a default browser title attribute popup
35239 under Add a block div beneath the field containing the error text
35240 side Add an error icon to the right of the field with a popup on hover
35241 [element id] Add the error text directly to the innerHTML of the specified element
35244 msgTarget : 'qtip',
35246 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35251 * @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.
35256 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35261 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35263 inputType : undefined,
35266 * @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).
35268 tabIndex : undefined,
35271 isFormField : true,
35276 * @property {Roo.Element} fieldEl
35277 * Element Containing the rendered Field (with label etc.)
35280 * @cfg {Mixed} value A value to initialize this field with.
35285 * @cfg {String} name The field's HTML name attribute.
35288 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35292 initComponent : function(){
35293 Roo.form.Field.superclass.initComponent.call(this);
35297 * Fires when this field receives input focus.
35298 * @param {Roo.form.Field} this
35303 * Fires when this field loses input focus.
35304 * @param {Roo.form.Field} this
35308 * @event specialkey
35309 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35310 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35311 * @param {Roo.form.Field} this
35312 * @param {Roo.EventObject} e The event object
35317 * Fires just before the field blurs if the field value has changed.
35318 * @param {Roo.form.Field} this
35319 * @param {Mixed} newValue The new value
35320 * @param {Mixed} oldValue The original value
35325 * Fires after the field has been marked as invalid.
35326 * @param {Roo.form.Field} this
35327 * @param {String} msg The validation message
35332 * Fires after the field has been validated with no errors.
35333 * @param {Roo.form.Field} this
35338 * Fires after the key up
35339 * @param {Roo.form.Field} this
35340 * @param {Roo.EventObject} e The event Object
35347 * Returns the name attribute of the field if available
35348 * @return {String} name The field name
35350 getName: function(){
35351 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35355 onRender : function(ct, position){
35356 Roo.form.Field.superclass.onRender.call(this, ct, position);
35358 var cfg = this.getAutoCreate();
35360 cfg.name = this.name || this.id;
35362 if(this.inputType){
35363 cfg.type = this.inputType;
35365 this.el = ct.createChild(cfg, position);
35367 var type = this.el.dom.type;
35369 if(type == 'password'){
35372 this.el.addClass('x-form-'+type);
35375 this.el.dom.readOnly = true;
35377 if(this.tabIndex !== undefined){
35378 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35381 this.el.addClass([this.fieldClass, this.cls]);
35386 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35387 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35388 * @return {Roo.form.Field} this
35390 applyTo : function(target){
35391 this.allowDomMove = false;
35392 this.el = Roo.get(target);
35393 this.render(this.el.dom.parentNode);
35398 initValue : function(){
35399 if(this.value !== undefined){
35400 this.setValue(this.value);
35401 }else if(this.el.dom.value.length > 0){
35402 this.setValue(this.el.dom.value);
35407 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35409 isDirty : function() {
35410 if(this.disabled) {
35413 return String(this.getValue()) !== String(this.originalValue);
35417 afterRender : function(){
35418 Roo.form.Field.superclass.afterRender.call(this);
35423 fireKey : function(e){
35424 //Roo.log('field ' + e.getKey());
35425 if(e.isNavKeyPress()){
35426 this.fireEvent("specialkey", this, e);
35431 * Resets the current field value to the originally loaded value and clears any validation messages
35433 reset : function(){
35434 this.setValue(this.originalValue);
35435 this.clearInvalid();
35439 initEvents : function(){
35440 // safari killled keypress - so keydown is now used..
35441 this.el.on("keydown" , this.fireKey, this);
35442 this.el.on("focus", this.onFocus, this);
35443 this.el.on("blur", this.onBlur, this);
35444 this.el.relayEvent('keyup', this);
35446 // reference to original value for reset
35447 this.originalValue = this.getValue();
35451 onFocus : function(){
35452 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35453 this.el.addClass(this.focusClass);
35455 if(!this.hasFocus){
35456 this.hasFocus = true;
35457 this.startValue = this.getValue();
35458 this.fireEvent("focus", this);
35462 beforeBlur : Roo.emptyFn,
35465 onBlur : function(){
35467 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35468 this.el.removeClass(this.focusClass);
35470 this.hasFocus = false;
35471 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35474 var v = this.getValue();
35475 if(String(v) !== String(this.startValue)){
35476 this.fireEvent('change', this, v, this.startValue);
35478 this.fireEvent("blur", this);
35482 * Returns whether or not the field value is currently valid
35483 * @param {Boolean} preventMark True to disable marking the field invalid
35484 * @return {Boolean} True if the value is valid, else false
35486 isValid : function(preventMark){
35490 var restore = this.preventMark;
35491 this.preventMark = preventMark === true;
35492 var v = this.validateValue(this.processValue(this.getRawValue()));
35493 this.preventMark = restore;
35498 * Validates the field value
35499 * @return {Boolean} True if the value is valid, else false
35501 validate : function(){
35502 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35503 this.clearInvalid();
35509 processValue : function(value){
35514 // Subclasses should provide the validation implementation by overriding this
35515 validateValue : function(value){
35520 * Mark this field as invalid
35521 * @param {String} msg The validation message
35523 markInvalid : function(msg){
35524 if(!this.rendered || this.preventMark){ // not rendered
35527 this.el.addClass(this.invalidClass);
35528 msg = msg || this.invalidText;
35529 switch(this.msgTarget){
35531 this.el.dom.qtip = msg;
35532 this.el.dom.qclass = 'x-form-invalid-tip';
35533 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35534 Roo.QuickTips.enable();
35538 this.el.dom.title = msg;
35542 var elp = this.el.findParent('.x-form-element', 5, true);
35543 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35544 this.errorEl.setWidth(elp.getWidth(true)-20);
35546 this.errorEl.update(msg);
35547 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35550 if(!this.errorIcon){
35551 var elp = this.el.findParent('.x-form-element', 5, true);
35552 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35554 this.alignErrorIcon();
35555 this.errorIcon.dom.qtip = msg;
35556 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35557 this.errorIcon.show();
35558 this.on('resize', this.alignErrorIcon, this);
35561 var t = Roo.getDom(this.msgTarget);
35563 t.style.display = this.msgDisplay;
35566 this.fireEvent('invalid', this, msg);
35570 alignErrorIcon : function(){
35571 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35575 * Clear any invalid styles/messages for this field
35577 clearInvalid : function(){
35578 if(!this.rendered || this.preventMark){ // not rendered
35581 this.el.removeClass(this.invalidClass);
35582 switch(this.msgTarget){
35584 this.el.dom.qtip = '';
35587 this.el.dom.title = '';
35591 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35595 if(this.errorIcon){
35596 this.errorIcon.dom.qtip = '';
35597 this.errorIcon.hide();
35598 this.un('resize', this.alignErrorIcon, this);
35602 var t = Roo.getDom(this.msgTarget);
35604 t.style.display = 'none';
35607 this.fireEvent('valid', this);
35611 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35612 * @return {Mixed} value The field value
35614 getRawValue : function(){
35615 var v = this.el.getValue();
35616 if(v === this.emptyText){
35623 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35624 * @return {Mixed} value The field value
35626 getValue : function(){
35627 var v = this.el.getValue();
35628 if(v === this.emptyText || v === undefined){
35635 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35636 * @param {Mixed} value The value to set
35638 setRawValue : function(v){
35639 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35643 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35644 * @param {Mixed} value The value to set
35646 setValue : function(v){
35649 this.el.dom.value = (v === null || v === undefined ? '' : v);
35654 adjustSize : function(w, h){
35655 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35656 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35660 adjustWidth : function(tag, w){
35661 tag = tag.toLowerCase();
35662 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35663 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35664 if(tag == 'input'){
35667 if(tag = 'textarea'){
35670 }else if(Roo.isOpera){
35671 if(tag == 'input'){
35674 if(tag = 'textarea'){
35684 // anything other than normal should be considered experimental
35685 Roo.form.Field.msgFx = {
35687 show: function(msgEl, f){
35688 msgEl.setDisplayed('block');
35691 hide : function(msgEl, f){
35692 msgEl.setDisplayed(false).update('');
35697 show: function(msgEl, f){
35698 msgEl.slideIn('t', {stopFx:true});
35701 hide : function(msgEl, f){
35702 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35707 show: function(msgEl, f){
35708 msgEl.fixDisplay();
35709 msgEl.alignTo(f.el, 'tl-tr');
35710 msgEl.slideIn('l', {stopFx:true});
35713 hide : function(msgEl, f){
35714 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35719 * Ext JS Library 1.1.1
35720 * Copyright(c) 2006-2007, Ext JS, LLC.
35722 * Originally Released Under LGPL - original licence link has changed is not relivant.
35725 * <script type="text/javascript">
35730 * @class Roo.form.TextField
35731 * @extends Roo.form.Field
35732 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35733 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35735 * Creates a new TextField
35736 * @param {Object} config Configuration options
35738 Roo.form.TextField = function(config){
35739 Roo.form.TextField.superclass.constructor.call(this, config);
35743 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35744 * according to the default logic, but this event provides a hook for the developer to apply additional
35745 * logic at runtime to resize the field if needed.
35746 * @param {Roo.form.Field} this This text field
35747 * @param {Number} width The new field width
35753 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35755 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35759 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35763 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35767 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35771 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35775 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35777 disableKeyFilter : false,
35779 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35783 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35787 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35789 maxLength : Number.MAX_VALUE,
35791 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35793 minLengthText : "The minimum length for this field is {0}",
35795 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35797 maxLengthText : "The maximum length for this field is {0}",
35799 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35801 selectOnFocus : false,
35803 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35805 blankText : "This field is required",
35807 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35808 * If available, this function will be called only after the basic validators all return true, and will be passed the
35809 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35813 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35814 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35815 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35819 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35823 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35827 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35828 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35830 emptyClass : 'x-form-empty-field',
35833 initEvents : function(){
35834 Roo.form.TextField.superclass.initEvents.call(this);
35835 if(this.validationEvent == 'keyup'){
35836 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35837 this.el.on('keyup', this.filterValidation, this);
35839 else if(this.validationEvent !== false){
35840 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35842 if(this.selectOnFocus || this.emptyText){
35843 this.on("focus", this.preFocus, this);
35844 if(this.emptyText){
35845 this.on('blur', this.postBlur, this);
35846 this.applyEmptyText();
35849 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35850 this.el.on("keypress", this.filterKeys, this);
35853 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35854 this.el.on("click", this.autoSize, this);
35858 processValue : function(value){
35859 if(this.stripCharsRe){
35860 var newValue = value.replace(this.stripCharsRe, '');
35861 if(newValue !== value){
35862 this.setRawValue(newValue);
35869 filterValidation : function(e){
35870 if(!e.isNavKeyPress()){
35871 this.validationTask.delay(this.validationDelay);
35876 onKeyUp : function(e){
35877 if(!e.isNavKeyPress()){
35883 * Resets the current field value to the originally-loaded value and clears any validation messages.
35884 * Also adds emptyText and emptyClass if the original value was blank.
35886 reset : function(){
35887 Roo.form.TextField.superclass.reset.call(this);
35888 this.applyEmptyText();
35891 applyEmptyText : function(){
35892 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35893 this.setRawValue(this.emptyText);
35894 this.el.addClass(this.emptyClass);
35899 preFocus : function(){
35900 if(this.emptyText){
35901 if(this.el.dom.value == this.emptyText){
35902 this.setRawValue('');
35904 this.el.removeClass(this.emptyClass);
35906 if(this.selectOnFocus){
35907 this.el.dom.select();
35912 postBlur : function(){
35913 this.applyEmptyText();
35917 filterKeys : function(e){
35918 var k = e.getKey();
35919 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35922 var c = e.getCharCode(), cc = String.fromCharCode(c);
35923 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35926 if(!this.maskRe.test(cc)){
35931 setValue : function(v){
35932 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35933 this.el.removeClass(this.emptyClass);
35935 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35936 this.applyEmptyText();
35941 * Validates a value according to the field's validation rules and marks the field as invalid
35942 * if the validation fails
35943 * @param {Mixed} value The value to validate
35944 * @return {Boolean} True if the value is valid, else false
35946 validateValue : function(value){
35947 if(value.length < 1 || value === this.emptyText){ // if it's blank
35948 if(this.allowBlank){
35949 this.clearInvalid();
35952 this.markInvalid(this.blankText);
35956 if(value.length < this.minLength){
35957 this.markInvalid(String.format(this.minLengthText, this.minLength));
35960 if(value.length > this.maxLength){
35961 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35965 var vt = Roo.form.VTypes;
35966 if(!vt[this.vtype](value, this)){
35967 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35971 if(typeof this.validator == "function"){
35972 var msg = this.validator(value);
35974 this.markInvalid(msg);
35978 if(this.regex && !this.regex.test(value)){
35979 this.markInvalid(this.regexText);
35986 * Selects text in this field
35987 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35988 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35990 selectText : function(start, end){
35991 var v = this.getRawValue();
35993 start = start === undefined ? 0 : start;
35994 end = end === undefined ? v.length : end;
35995 var d = this.el.dom;
35996 if(d.setSelectionRange){
35997 d.setSelectionRange(start, end);
35998 }else if(d.createTextRange){
35999 var range = d.createTextRange();
36000 range.moveStart("character", start);
36001 range.moveEnd("character", v.length-end);
36008 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36009 * This only takes effect if grow = true, and fires the autosize event.
36011 autoSize : function(){
36012 if(!this.grow || !this.rendered){
36016 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36019 var v = el.dom.value;
36020 var d = document.createElement('div');
36021 d.appendChild(document.createTextNode(v));
36025 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36026 this.el.setWidth(w);
36027 this.fireEvent("autosize", this, w);
36031 * Ext JS Library 1.1.1
36032 * Copyright(c) 2006-2007, Ext JS, LLC.
36034 * Originally Released Under LGPL - original licence link has changed is not relivant.
36037 * <script type="text/javascript">
36041 * @class Roo.form.Hidden
36042 * @extends Roo.form.TextField
36043 * Simple Hidden element used on forms
36045 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36048 * Creates a new Hidden form element.
36049 * @param {Object} config Configuration options
36054 // easy hidden field...
36055 Roo.form.Hidden = function(config){
36056 Roo.form.Hidden.superclass.constructor.call(this, config);
36059 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36061 inputType: 'hidden',
36064 labelSeparator: '',
36066 itemCls : 'x-form-item-display-none'
36074 * Ext JS Library 1.1.1
36075 * Copyright(c) 2006-2007, Ext JS, LLC.
36077 * Originally Released Under LGPL - original licence link has changed is not relivant.
36080 * <script type="text/javascript">
36084 * @class Roo.form.TriggerField
36085 * @extends Roo.form.TextField
36086 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36087 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36088 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36089 * for which you can provide a custom implementation. For example:
36091 var trigger = new Roo.form.TriggerField();
36092 trigger.onTriggerClick = myTriggerFn;
36093 trigger.applyTo('my-field');
36096 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36097 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36098 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36099 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36101 * Create a new TriggerField.
36102 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36103 * to the base TextField)
36105 Roo.form.TriggerField = function(config){
36106 this.mimicing = false;
36107 Roo.form.TriggerField.superclass.constructor.call(this, config);
36110 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36112 * @cfg {String} triggerClass A CSS class to apply to the trigger
36115 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36116 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36118 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36120 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36124 /** @cfg {Boolean} grow @hide */
36125 /** @cfg {Number} growMin @hide */
36126 /** @cfg {Number} growMax @hide */
36132 autoSize: Roo.emptyFn,
36136 deferHeight : true,
36139 actionMode : 'wrap',
36141 onResize : function(w, h){
36142 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36143 if(typeof w == 'number'){
36144 var x = w - this.trigger.getWidth();
36145 this.el.setWidth(this.adjustWidth('input', x));
36146 this.trigger.setStyle('left', x+'px');
36151 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36154 getResizeEl : function(){
36159 getPositionEl : function(){
36164 alignErrorIcon : function(){
36165 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36169 onRender : function(ct, position){
36170 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36171 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36172 this.trigger = this.wrap.createChild(this.triggerConfig ||
36173 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36174 if(this.hideTrigger){
36175 this.trigger.setDisplayed(false);
36177 this.initTrigger();
36179 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36184 initTrigger : function(){
36185 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36186 this.trigger.addClassOnOver('x-form-trigger-over');
36187 this.trigger.addClassOnClick('x-form-trigger-click');
36191 onDestroy : function(){
36193 this.trigger.removeAllListeners();
36194 this.trigger.remove();
36197 this.wrap.remove();
36199 Roo.form.TriggerField.superclass.onDestroy.call(this);
36203 onFocus : function(){
36204 Roo.form.TriggerField.superclass.onFocus.call(this);
36205 if(!this.mimicing){
36206 this.wrap.addClass('x-trigger-wrap-focus');
36207 this.mimicing = true;
36208 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36209 if(this.monitorTab){
36210 this.el.on("keydown", this.checkTab, this);
36216 checkTab : function(e){
36217 if(e.getKey() == e.TAB){
36218 this.triggerBlur();
36223 onBlur : function(){
36228 mimicBlur : function(e, t){
36229 if(!this.wrap.contains(t) && this.validateBlur()){
36230 this.triggerBlur();
36235 triggerBlur : function(){
36236 this.mimicing = false;
36237 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36238 if(this.monitorTab){
36239 this.el.un("keydown", this.checkTab, this);
36241 this.wrap.removeClass('x-trigger-wrap-focus');
36242 Roo.form.TriggerField.superclass.onBlur.call(this);
36246 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36247 validateBlur : function(e, t){
36252 onDisable : function(){
36253 Roo.form.TriggerField.superclass.onDisable.call(this);
36255 this.wrap.addClass('x-item-disabled');
36260 onEnable : function(){
36261 Roo.form.TriggerField.superclass.onEnable.call(this);
36263 this.wrap.removeClass('x-item-disabled');
36268 onShow : function(){
36269 var ae = this.getActionEl();
36272 ae.dom.style.display = '';
36273 ae.dom.style.visibility = 'visible';
36279 onHide : function(){
36280 var ae = this.getActionEl();
36281 ae.dom.style.display = 'none';
36285 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36286 * by an implementing function.
36288 * @param {EventObject} e
36290 onTriggerClick : Roo.emptyFn
36293 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36294 // to be extended by an implementing class. For an example of implementing this class, see the custom
36295 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36296 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36297 initComponent : function(){
36298 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36300 this.triggerConfig = {
36301 tag:'span', cls:'x-form-twin-triggers', cn:[
36302 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36303 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36307 getTrigger : function(index){
36308 return this.triggers[index];
36311 initTrigger : function(){
36312 var ts = this.trigger.select('.x-form-trigger', true);
36313 this.wrap.setStyle('overflow', 'hidden');
36314 var triggerField = this;
36315 ts.each(function(t, all, index){
36316 t.hide = function(){
36317 var w = triggerField.wrap.getWidth();
36318 this.dom.style.display = 'none';
36319 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36321 t.show = function(){
36322 var w = triggerField.wrap.getWidth();
36323 this.dom.style.display = '';
36324 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36326 var triggerIndex = 'Trigger'+(index+1);
36328 if(this['hide'+triggerIndex]){
36329 t.dom.style.display = 'none';
36331 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36332 t.addClassOnOver('x-form-trigger-over');
36333 t.addClassOnClick('x-form-trigger-click');
36335 this.triggers = ts.elements;
36338 onTrigger1Click : Roo.emptyFn,
36339 onTrigger2Click : Roo.emptyFn
36342 * Ext JS Library 1.1.1
36343 * Copyright(c) 2006-2007, Ext JS, LLC.
36345 * Originally Released Under LGPL - original licence link has changed is not relivant.
36348 * <script type="text/javascript">
36352 * @class Roo.form.TextArea
36353 * @extends Roo.form.TextField
36354 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36355 * support for auto-sizing.
36357 * Creates a new TextArea
36358 * @param {Object} config Configuration options
36360 Roo.form.TextArea = function(config){
36361 Roo.form.TextArea.superclass.constructor.call(this, config);
36362 // these are provided exchanges for backwards compat
36363 // minHeight/maxHeight were replaced by growMin/growMax to be
36364 // compatible with TextField growing config values
36365 if(this.minHeight !== undefined){
36366 this.growMin = this.minHeight;
36368 if(this.maxHeight !== undefined){
36369 this.growMax = this.maxHeight;
36373 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36375 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36379 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36383 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36384 * in the field (equivalent to setting overflow: hidden, defaults to false)
36386 preventScrollbars: false,
36388 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36389 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36393 onRender : function(ct, position){
36395 this.defaultAutoCreate = {
36397 style:"width:300px;height:60px;",
36398 autocomplete: "off"
36401 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36403 this.textSizeEl = Roo.DomHelper.append(document.body, {
36404 tag: "pre", cls: "x-form-grow-sizer"
36406 if(this.preventScrollbars){
36407 this.el.setStyle("overflow", "hidden");
36409 this.el.setHeight(this.growMin);
36413 onDestroy : function(){
36414 if(this.textSizeEl){
36415 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36417 Roo.form.TextArea.superclass.onDestroy.call(this);
36421 onKeyUp : function(e){
36422 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36428 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36429 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36431 autoSize : function(){
36432 if(!this.grow || !this.textSizeEl){
36436 var v = el.dom.value;
36437 var ts = this.textSizeEl;
36440 ts.appendChild(document.createTextNode(v));
36443 Roo.fly(ts).setWidth(this.el.getWidth());
36445 v = "  ";
36448 v = v.replace(/\n/g, '<p> </p>');
36450 v += " \n ";
36453 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36454 if(h != this.lastHeight){
36455 this.lastHeight = h;
36456 this.el.setHeight(h);
36457 this.fireEvent("autosize", this, h);
36462 * Ext JS Library 1.1.1
36463 * Copyright(c) 2006-2007, Ext JS, LLC.
36465 * Originally Released Under LGPL - original licence link has changed is not relivant.
36468 * <script type="text/javascript">
36473 * @class Roo.form.NumberField
36474 * @extends Roo.form.TextField
36475 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36477 * Creates a new NumberField
36478 * @param {Object} config Configuration options
36480 Roo.form.NumberField = function(config){
36481 Roo.form.NumberField.superclass.constructor.call(this, config);
36484 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36486 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36488 fieldClass: "x-form-field x-form-num-field",
36490 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36492 allowDecimals : true,
36494 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36496 decimalSeparator : ".",
36498 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36500 decimalPrecision : 2,
36502 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36504 allowNegative : true,
36506 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36508 minValue : Number.NEGATIVE_INFINITY,
36510 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36512 maxValue : Number.MAX_VALUE,
36514 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36516 minText : "The minimum value for this field is {0}",
36518 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36520 maxText : "The maximum value for this field is {0}",
36522 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36523 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36525 nanText : "{0} is not a valid number",
36528 initEvents : function(){
36529 Roo.form.NumberField.superclass.initEvents.call(this);
36530 var allowed = "0123456789";
36531 if(this.allowDecimals){
36532 allowed += this.decimalSeparator;
36534 if(this.allowNegative){
36537 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36538 var keyPress = function(e){
36539 var k = e.getKey();
36540 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36543 var c = e.getCharCode();
36544 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36548 this.el.on("keypress", keyPress, this);
36552 validateValue : function(value){
36553 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36556 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36559 var num = this.parseValue(value);
36561 this.markInvalid(String.format(this.nanText, value));
36564 if(num < this.minValue){
36565 this.markInvalid(String.format(this.minText, this.minValue));
36568 if(num > this.maxValue){
36569 this.markInvalid(String.format(this.maxText, this.maxValue));
36575 getValue : function(){
36576 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36580 parseValue : function(value){
36581 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36582 return isNaN(value) ? '' : value;
36586 fixPrecision : function(value){
36587 var nan = isNaN(value);
36588 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36589 return nan ? '' : value;
36591 return parseFloat(value).toFixed(this.decimalPrecision);
36594 setValue : function(v){
36595 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36599 decimalPrecisionFcn : function(v){
36600 return Math.floor(v);
36603 beforeBlur : function(){
36604 var v = this.parseValue(this.getRawValue());
36606 this.setValue(this.fixPrecision(v));
36611 * Ext JS Library 1.1.1
36612 * Copyright(c) 2006-2007, Ext JS, LLC.
36614 * Originally Released Under LGPL - original licence link has changed is not relivant.
36617 * <script type="text/javascript">
36621 * @class Roo.form.DateField
36622 * @extends Roo.form.TriggerField
36623 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36625 * Create a new DateField
36626 * @param {Object} config
36628 Roo.form.DateField = function(config){
36629 Roo.form.DateField.superclass.constructor.call(this, config);
36635 * Fires when a date is selected
36636 * @param {Roo.form.DateField} combo This combo box
36637 * @param {Date} date The date selected
36644 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36645 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36646 this.ddMatch = null;
36647 if(this.disabledDates){
36648 var dd = this.disabledDates;
36650 for(var i = 0; i < dd.length; i++){
36652 if(i != dd.length-1) re += "|";
36654 this.ddMatch = new RegExp(re + ")");
36658 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36660 * @cfg {String} format
36661 * The default date format string which can be overriden for localization support. The format must be
36662 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36666 * @cfg {String} altFormats
36667 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36668 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36670 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36672 * @cfg {Array} disabledDays
36673 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36675 disabledDays : null,
36677 * @cfg {String} disabledDaysText
36678 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36680 disabledDaysText : "Disabled",
36682 * @cfg {Array} disabledDates
36683 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36684 * expression so they are very powerful. Some examples:
36686 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36687 * <li>["03/08", "09/16"] would disable those days for every year</li>
36688 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36689 * <li>["03/../2006"] would disable every day in March 2006</li>
36690 * <li>["^03"] would disable every day in every March</li>
36692 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36693 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36695 disabledDates : null,
36697 * @cfg {String} disabledDatesText
36698 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36700 disabledDatesText : "Disabled",
36702 * @cfg {Date/String} minValue
36703 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36704 * valid format (defaults to null).
36708 * @cfg {Date/String} maxValue
36709 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36710 * valid format (defaults to null).
36714 * @cfg {String} minText
36715 * The error text to display when the date in the cell is before minValue (defaults to
36716 * 'The date in this field must be after {minValue}').
36718 minText : "The date in this field must be equal to or after {0}",
36720 * @cfg {String} maxText
36721 * The error text to display when the date in the cell is after maxValue (defaults to
36722 * 'The date in this field must be before {maxValue}').
36724 maxText : "The date in this field must be equal to or before {0}",
36726 * @cfg {String} invalidText
36727 * The error text to display when the date in the field is invalid (defaults to
36728 * '{value} is not a valid date - it must be in the format {format}').
36730 invalidText : "{0} is not a valid date - it must be in the format {1}",
36732 * @cfg {String} triggerClass
36733 * An additional CSS class used to style the trigger button. The trigger will always get the
36734 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36735 * which displays a calendar icon).
36737 triggerClass : 'x-form-date-trigger',
36741 * @cfg {bool} useIso
36742 * if enabled, then the date field will use a hidden field to store the
36743 * real value as iso formated date. default (false)
36747 * @cfg {String/Object} autoCreate
36748 * A DomHelper element spec, or true for a default element spec (defaults to
36749 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36752 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36755 hiddenField: false,
36757 onRender : function(ct, position)
36759 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36761 this.el.dom.removeAttribute('name');
36762 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36764 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36765 // prevent input submission
36766 this.hiddenName = this.name;
36773 validateValue : function(value)
36775 value = this.formatDate(value);
36776 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36779 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36782 var svalue = value;
36783 value = this.parseDate(value);
36785 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36788 var time = value.getTime();
36789 if(this.minValue && time < this.minValue.getTime()){
36790 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36793 if(this.maxValue && time > this.maxValue.getTime()){
36794 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36797 if(this.disabledDays){
36798 var day = value.getDay();
36799 for(var i = 0; i < this.disabledDays.length; i++) {
36800 if(day === this.disabledDays[i]){
36801 this.markInvalid(this.disabledDaysText);
36806 var fvalue = this.formatDate(value);
36807 if(this.ddMatch && this.ddMatch.test(fvalue)){
36808 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36815 // Provides logic to override the default TriggerField.validateBlur which just returns true
36816 validateBlur : function(){
36817 return !this.menu || !this.menu.isVisible();
36821 * Returns the current date value of the date field.
36822 * @return {Date} The date value
36824 getValue : function(){
36826 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36830 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36831 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36832 * (the default format used is "m/d/y").
36835 //All of these calls set the same date value (May 4, 2006)
36837 //Pass a date object:
36838 var dt = new Date('5/4/06');
36839 dateField.setValue(dt);
36841 //Pass a date string (default format):
36842 dateField.setValue('5/4/06');
36844 //Pass a date string (custom format):
36845 dateField.format = 'Y-m-d';
36846 dateField.setValue('2006-5-4');
36848 * @param {String/Date} date The date or valid date string
36850 setValue : function(date){
36851 if (this.hiddenField) {
36852 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36854 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36858 parseDate : function(value){
36859 if(!value || value instanceof Date){
36862 var v = Date.parseDate(value, this.format);
36863 if(!v && this.altFormats){
36864 if(!this.altFormatsArray){
36865 this.altFormatsArray = this.altFormats.split("|");
36867 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36868 v = Date.parseDate(value, this.altFormatsArray[i]);
36875 formatDate : function(date, fmt){
36876 return (!date || !(date instanceof Date)) ?
36877 date : date.dateFormat(fmt || this.format);
36882 select: function(m, d){
36884 this.fireEvent('select', this, d);
36886 show : function(){ // retain focus styling
36890 this.focus.defer(10, this);
36891 var ml = this.menuListeners;
36892 this.menu.un("select", ml.select, this);
36893 this.menu.un("show", ml.show, this);
36894 this.menu.un("hide", ml.hide, this);
36899 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36900 onTriggerClick : function(){
36904 if(this.menu == null){
36905 this.menu = new Roo.menu.DateMenu();
36907 Roo.apply(this.menu.picker, {
36908 showClear: this.allowBlank,
36909 minDate : this.minValue,
36910 maxDate : this.maxValue,
36911 disabledDatesRE : this.ddMatch,
36912 disabledDatesText : this.disabledDatesText,
36913 disabledDays : this.disabledDays,
36914 disabledDaysText : this.disabledDaysText,
36915 format : this.format,
36916 minText : String.format(this.minText, this.formatDate(this.minValue)),
36917 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36919 this.menu.on(Roo.apply({}, this.menuListeners, {
36922 this.menu.picker.setValue(this.getValue() || new Date());
36923 this.menu.show(this.el, "tl-bl?");
36926 beforeBlur : function(){
36927 var v = this.parseDate(this.getRawValue());
36933 /** @cfg {Boolean} grow @hide */
36934 /** @cfg {Number} growMin @hide */
36935 /** @cfg {Number} growMax @hide */
36942 * Ext JS Library 1.1.1
36943 * Copyright(c) 2006-2007, Ext JS, LLC.
36945 * Originally Released Under LGPL - original licence link has changed is not relivant.
36948 * <script type="text/javascript">
36953 * @class Roo.form.ComboBox
36954 * @extends Roo.form.TriggerField
36955 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36957 * Create a new ComboBox.
36958 * @param {Object} config Configuration options
36960 Roo.form.ComboBox = function(config){
36961 Roo.form.ComboBox.superclass.constructor.call(this, config);
36965 * Fires when the dropdown list is expanded
36966 * @param {Roo.form.ComboBox} combo This combo box
36971 * Fires when the dropdown list is collapsed
36972 * @param {Roo.form.ComboBox} combo This combo box
36976 * @event beforeselect
36977 * Fires before a list item is selected. Return false to cancel the selection.
36978 * @param {Roo.form.ComboBox} combo This combo box
36979 * @param {Roo.data.Record} record The data record returned from the underlying store
36980 * @param {Number} index The index of the selected item in the dropdown list
36982 'beforeselect' : true,
36985 * Fires when a list item is selected
36986 * @param {Roo.form.ComboBox} combo This combo box
36987 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36988 * @param {Number} index The index of the selected item in the dropdown list
36992 * @event beforequery
36993 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36994 * The event object passed has these properties:
36995 * @param {Roo.form.ComboBox} combo This combo box
36996 * @param {String} query The query
36997 * @param {Boolean} forceAll true to force "all" query
36998 * @param {Boolean} cancel true to cancel the query
36999 * @param {Object} e The query event object
37001 'beforequery': true,
37004 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37005 * @param {Roo.form.ComboBox} combo This combo box
37010 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37011 * @param {Roo.form.ComboBox} combo This combo box
37012 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37018 if(this.transform){
37019 this.allowDomMove = false;
37020 var s = Roo.getDom(this.transform);
37021 if(!this.hiddenName){
37022 this.hiddenName = s.name;
37025 this.mode = 'local';
37026 var d = [], opts = s.options;
37027 for(var i = 0, len = opts.length;i < len; i++){
37029 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37031 this.value = value;
37033 d.push([value, o.text]);
37035 this.store = new Roo.data.SimpleStore({
37037 fields: ['value', 'text'],
37040 this.valueField = 'value';
37041 this.displayField = 'text';
37043 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37044 if(!this.lazyRender){
37045 this.target = true;
37046 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37047 s.parentNode.removeChild(s); // remove it
37048 this.render(this.el.parentNode);
37050 s.parentNode.removeChild(s); // remove it
37055 this.store = Roo.factory(this.store, Roo.data);
37058 this.selectedIndex = -1;
37059 if(this.mode == 'local'){
37060 if(config.queryDelay === undefined){
37061 this.queryDelay = 10;
37063 if(config.minChars === undefined){
37069 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37071 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37074 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37075 * rendering into an Roo.Editor, defaults to false)
37078 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37079 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37082 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37085 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37086 * the dropdown list (defaults to undefined, with no header element)
37090 * @cfg {String/Roo.Template} tpl The template to use to render the output
37094 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37096 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37098 listWidth: undefined,
37100 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37101 * mode = 'remote' or 'text' if mode = 'local')
37103 displayField: undefined,
37105 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37106 * mode = 'remote' or 'value' if mode = 'local').
37107 * Note: use of a valueField requires the user make a selection
37108 * in order for a value to be mapped.
37110 valueField: undefined,
37112 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37113 * field's data value (defaults to the underlying DOM element's name)
37115 hiddenName: undefined,
37117 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37121 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37123 selectedClass: 'x-combo-selected',
37125 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37126 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37127 * which displays a downward arrow icon).
37129 triggerClass : 'x-form-arrow-trigger',
37131 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37135 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37136 * anchor positions (defaults to 'tl-bl')
37138 listAlign: 'tl-bl?',
37140 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37144 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37145 * query specified by the allQuery config option (defaults to 'query')
37147 triggerAction: 'query',
37149 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37150 * (defaults to 4, does not apply if editable = false)
37154 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37155 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37159 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37160 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37164 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37165 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37169 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37170 * when editable = true (defaults to false)
37172 selectOnFocus:false,
37174 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37176 queryParam: 'query',
37178 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37179 * when mode = 'remote' (defaults to 'Loading...')
37181 loadingText: 'Loading...',
37183 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37187 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37191 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37192 * traditional select (defaults to true)
37196 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37200 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37204 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37205 * listWidth has a higher value)
37209 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37210 * allow the user to set arbitrary text into the field (defaults to false)
37212 forceSelection:false,
37214 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37215 * if typeAhead = true (defaults to 250)
37217 typeAheadDelay : 250,
37219 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37220 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37222 valueNotFoundText : undefined,
37224 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37226 blockFocus : false,
37229 * @cfg {Boolean} disableClear Disable showing of clear button.
37231 disableClear : false,
37233 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37235 alwaysQuery : false,
37243 onRender : function(ct, position){
37244 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37245 if(this.hiddenName){
37246 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37248 this.hiddenField.value =
37249 this.hiddenValue !== undefined ? this.hiddenValue :
37250 this.value !== undefined ? this.value : '';
37252 // prevent input submission
37253 this.el.dom.removeAttribute('name');
37256 this.el.dom.setAttribute('autocomplete', 'off');
37259 var cls = 'x-combo-list';
37261 this.list = new Roo.Layer({
37262 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37265 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37266 this.list.setWidth(lw);
37267 this.list.swallowEvent('mousewheel');
37268 this.assetHeight = 0;
37271 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37272 this.assetHeight += this.header.getHeight();
37275 this.innerList = this.list.createChild({cls:cls+'-inner'});
37276 this.innerList.on('mouseover', this.onViewOver, this);
37277 this.innerList.on('mousemove', this.onViewMove, this);
37278 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37280 if(this.allowBlank && !this.pageSize && !this.disableClear){
37281 this.footer = this.list.createChild({cls:cls+'-ft'});
37282 this.pageTb = new Roo.Toolbar(this.footer);
37286 this.footer = this.list.createChild({cls:cls+'-ft'});
37287 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37288 {pageSize: this.pageSize});
37292 if (this.pageTb && this.allowBlank && !this.disableClear) {
37294 this.pageTb.add(new Roo.Toolbar.Fill(), {
37295 cls: 'x-btn-icon x-btn-clear',
37297 handler: function()
37300 _this.clearValue();
37301 _this.onSelect(false, -1);
37306 this.assetHeight += this.footer.getHeight();
37311 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37314 this.view = new Roo.View(this.innerList, this.tpl, {
37315 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37318 this.view.on('click', this.onViewClick, this);
37320 this.store.on('beforeload', this.onBeforeLoad, this);
37321 this.store.on('load', this.onLoad, this);
37322 this.store.on('loadexception', this.collapse, this);
37324 if(this.resizable){
37325 this.resizer = new Roo.Resizable(this.list, {
37326 pinned:true, handles:'se'
37328 this.resizer.on('resize', function(r, w, h){
37329 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37330 this.listWidth = w;
37331 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37332 this.restrictHeight();
37334 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37336 if(!this.editable){
37337 this.editable = true;
37338 this.setEditable(false);
37342 if (typeof(this.events.add.listeners) != 'undefined') {
37344 this.addicon = this.wrap.createChild(
37345 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37347 this.addicon.on('click', function(e) {
37348 this.fireEvent('add', this);
37351 if (typeof(this.events.edit.listeners) != 'undefined') {
37353 this.editicon = this.wrap.createChild(
37354 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37355 if (this.addicon) {
37356 this.editicon.setStyle('margin-left', '40px');
37358 this.editicon.on('click', function(e) {
37360 // we fire even if inothing is selected..
37361 this.fireEvent('edit', this, this.lastData );
37371 initEvents : function(){
37372 Roo.form.ComboBox.superclass.initEvents.call(this);
37374 this.keyNav = new Roo.KeyNav(this.el, {
37375 "up" : function(e){
37376 this.inKeyMode = true;
37380 "down" : function(e){
37381 if(!this.isExpanded()){
37382 this.onTriggerClick();
37384 this.inKeyMode = true;
37389 "enter" : function(e){
37390 this.onViewClick();
37394 "esc" : function(e){
37398 "tab" : function(e){
37399 this.onViewClick(false);
37405 doRelay : function(foo, bar, hname){
37406 if(hname == 'down' || this.scope.isExpanded()){
37407 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37414 this.queryDelay = Math.max(this.queryDelay || 10,
37415 this.mode == 'local' ? 10 : 250);
37416 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37417 if(this.typeAhead){
37418 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37420 if(this.editable !== false){
37421 this.el.on("keyup", this.onKeyUp, this);
37423 if(this.forceSelection){
37424 this.on('blur', this.doForce, this);
37428 onDestroy : function(){
37430 this.view.setStore(null);
37431 this.view.el.removeAllListeners();
37432 this.view.el.remove();
37433 this.view.purgeListeners();
37436 this.list.destroy();
37439 this.store.un('beforeload', this.onBeforeLoad, this);
37440 this.store.un('load', this.onLoad, this);
37441 this.store.un('loadexception', this.collapse, this);
37443 Roo.form.ComboBox.superclass.onDestroy.call(this);
37447 fireKey : function(e){
37448 if(e.isNavKeyPress() && !this.list.isVisible()){
37449 this.fireEvent("specialkey", this, e);
37454 onResize: function(w, h){
37455 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37457 if(typeof w != 'number'){
37458 // we do not handle it!?!?
37461 var tw = this.trigger.getWidth();
37462 tw += this.addicon ? this.addicon.getWidth() : 0;
37463 tw += this.editicon ? this.editicon.getWidth() : 0;
37465 this.el.setWidth( this.adjustWidth('input', x));
37467 this.trigger.setStyle('left', x+'px');
37469 if(this.list && this.listWidth === undefined){
37470 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37471 this.list.setWidth(lw);
37472 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37480 * Allow or prevent the user from directly editing the field text. If false is passed,
37481 * the user will only be able to select from the items defined in the dropdown list. This method
37482 * is the runtime equivalent of setting the 'editable' config option at config time.
37483 * @param {Boolean} value True to allow the user to directly edit the field text
37485 setEditable : function(value){
37486 if(value == this.editable){
37489 this.editable = value;
37491 this.el.dom.setAttribute('readOnly', true);
37492 this.el.on('mousedown', this.onTriggerClick, this);
37493 this.el.addClass('x-combo-noedit');
37495 this.el.dom.setAttribute('readOnly', false);
37496 this.el.un('mousedown', this.onTriggerClick, this);
37497 this.el.removeClass('x-combo-noedit');
37502 onBeforeLoad : function(){
37503 if(!this.hasFocus){
37506 this.innerList.update(this.loadingText ?
37507 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37508 this.restrictHeight();
37509 this.selectedIndex = -1;
37513 onLoad : function(){
37514 if(!this.hasFocus){
37517 if(this.store.getCount() > 0){
37519 this.restrictHeight();
37520 if(this.lastQuery == this.allQuery){
37522 this.el.dom.select();
37524 if(!this.selectByValue(this.value, true)){
37525 this.select(0, true);
37529 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37530 this.taTask.delay(this.typeAheadDelay);
37534 this.onEmptyResults();
37540 onTypeAhead : function(){
37541 if(this.store.getCount() > 0){
37542 var r = this.store.getAt(0);
37543 var newValue = r.data[this.displayField];
37544 var len = newValue.length;
37545 var selStart = this.getRawValue().length;
37546 if(selStart != len){
37547 this.setRawValue(newValue);
37548 this.selectText(selStart, newValue.length);
37554 onSelect : function(record, index){
37555 if(this.fireEvent('beforeselect', this, record, index) !== false){
37556 this.setFromData(index > -1 ? record.data : false);
37558 this.fireEvent('select', this, record, index);
37563 * Returns the currently selected field value or empty string if no value is set.
37564 * @return {String} value The selected value
37566 getValue : function(){
37567 if(this.valueField){
37568 return typeof this.value != 'undefined' ? this.value : '';
37570 return Roo.form.ComboBox.superclass.getValue.call(this);
37575 * Clears any text/value currently set in the field
37577 clearValue : function(){
37578 if(this.hiddenField){
37579 this.hiddenField.value = '';
37582 this.setRawValue('');
37583 this.lastSelectionText = '';
37584 this.applyEmptyText();
37588 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37589 * will be displayed in the field. If the value does not match the data value of an existing item,
37590 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37591 * Otherwise the field will be blank (although the value will still be set).
37592 * @param {String} value The value to match
37594 setValue : function(v){
37596 if(this.valueField){
37597 var r = this.findRecord(this.valueField, v);
37599 text = r.data[this.displayField];
37600 }else if(this.valueNotFoundText !== undefined){
37601 text = this.valueNotFoundText;
37604 this.lastSelectionText = text;
37605 if(this.hiddenField){
37606 this.hiddenField.value = v;
37608 Roo.form.ComboBox.superclass.setValue.call(this, text);
37612 * @property {Object} the last set data for the element
37617 * Sets the value of the field based on a object which is related to the record format for the store.
37618 * @param {Object} value the value to set as. or false on reset?
37620 setFromData : function(o){
37621 var dv = ''; // display value
37622 var vv = ''; // value value..
37624 if (this.displayField) {
37625 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37627 // this is an error condition!!!
37628 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37631 if(this.valueField){
37632 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37634 if(this.hiddenField){
37635 this.hiddenField.value = vv;
37637 this.lastSelectionText = dv;
37638 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37642 // no hidden field.. - we store the value in 'value', but still display
37643 // display field!!!!
37644 this.lastSelectionText = dv;
37645 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37651 reset : function(){
37652 // overridden so that last data is reset..
37653 this.setValue(this.originalValue);
37654 this.clearInvalid();
37655 this.lastData = false;
37658 findRecord : function(prop, value){
37660 if(this.store.getCount() > 0){
37661 this.store.each(function(r){
37662 if(r.data[prop] == value){
37672 onViewMove : function(e, t){
37673 this.inKeyMode = false;
37677 onViewOver : function(e, t){
37678 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37681 var item = this.view.findItemFromChild(t);
37683 var index = this.view.indexOf(item);
37684 this.select(index, false);
37689 onViewClick : function(doFocus){
37690 var index = this.view.getSelectedIndexes()[0];
37691 var r = this.store.getAt(index);
37693 this.onSelect(r, index);
37695 if(doFocus !== false && !this.blockFocus){
37701 restrictHeight : function(){
37702 this.innerList.dom.style.height = '';
37703 var inner = this.innerList.dom;
37704 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37705 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37706 this.list.beginUpdate();
37707 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37708 this.list.alignTo(this.el, this.listAlign);
37709 this.list.endUpdate();
37713 onEmptyResults : function(){
37718 * Returns true if the dropdown list is expanded, else false.
37720 isExpanded : function(){
37721 return this.list.isVisible();
37725 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37726 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37727 * @param {String} value The data value of the item to select
37728 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37729 * selected item if it is not currently in view (defaults to true)
37730 * @return {Boolean} True if the value matched an item in the list, else false
37732 selectByValue : function(v, scrollIntoView){
37733 if(v !== undefined && v !== null){
37734 var r = this.findRecord(this.valueField || this.displayField, v);
37736 this.select(this.store.indexOf(r), scrollIntoView);
37744 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37745 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37746 * @param {Number} index The zero-based index of the list item to select
37747 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37748 * selected item if it is not currently in view (defaults to true)
37750 select : function(index, scrollIntoView){
37751 this.selectedIndex = index;
37752 this.view.select(index);
37753 if(scrollIntoView !== false){
37754 var el = this.view.getNode(index);
37756 this.innerList.scrollChildIntoView(el, false);
37762 selectNext : function(){
37763 var ct = this.store.getCount();
37765 if(this.selectedIndex == -1){
37767 }else if(this.selectedIndex < ct-1){
37768 this.select(this.selectedIndex+1);
37774 selectPrev : function(){
37775 var ct = this.store.getCount();
37777 if(this.selectedIndex == -1){
37779 }else if(this.selectedIndex != 0){
37780 this.select(this.selectedIndex-1);
37786 onKeyUp : function(e){
37787 if(this.editable !== false && !e.isSpecialKey()){
37788 this.lastKey = e.getKey();
37789 this.dqTask.delay(this.queryDelay);
37794 validateBlur : function(){
37795 return !this.list || !this.list.isVisible();
37799 initQuery : function(){
37800 this.doQuery(this.getRawValue());
37804 doForce : function(){
37805 if(this.el.dom.value.length > 0){
37806 this.el.dom.value =
37807 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37808 this.applyEmptyText();
37813 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37814 * query allowing the query action to be canceled if needed.
37815 * @param {String} query The SQL query to execute
37816 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37817 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37818 * saved in the current store (defaults to false)
37820 doQuery : function(q, forceAll){
37821 if(q === undefined || q === null){
37826 forceAll: forceAll,
37830 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37834 forceAll = qe.forceAll;
37835 if(forceAll === true || (q.length >= this.minChars)){
37836 if(this.lastQuery != q || this.alwaysQuery){
37837 this.lastQuery = q;
37838 if(this.mode == 'local'){
37839 this.selectedIndex = -1;
37841 this.store.clearFilter();
37843 this.store.filter(this.displayField, q);
37847 this.store.baseParams[this.queryParam] = q;
37849 params: this.getParams(q)
37854 this.selectedIndex = -1;
37861 getParams : function(q){
37863 //p[this.queryParam] = q;
37866 p.limit = this.pageSize;
37872 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37874 collapse : function(){
37875 if(!this.isExpanded()){
37879 Roo.get(document).un('mousedown', this.collapseIf, this);
37880 Roo.get(document).un('mousewheel', this.collapseIf, this);
37881 if (!this.editable) {
37882 Roo.get(document).un('keydown', this.listKeyPress, this);
37884 this.fireEvent('collapse', this);
37888 collapseIf : function(e){
37889 if(!e.within(this.wrap) && !e.within(this.list)){
37895 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37897 expand : function(){
37898 if(this.isExpanded() || !this.hasFocus){
37901 this.list.alignTo(this.el, this.listAlign);
37903 Roo.get(document).on('mousedown', this.collapseIf, this);
37904 Roo.get(document).on('mousewheel', this.collapseIf, this);
37905 if (!this.editable) {
37906 Roo.get(document).on('keydown', this.listKeyPress, this);
37909 this.fireEvent('expand', this);
37913 // Implements the default empty TriggerField.onTriggerClick function
37914 onTriggerClick : function(){
37918 if(this.isExpanded()){
37920 if (!this.blockFocus) {
37925 this.hasFocus = true;
37926 if(this.triggerAction == 'all') {
37927 this.doQuery(this.allQuery, true);
37929 this.doQuery(this.getRawValue());
37931 if (!this.blockFocus) {
37936 listKeyPress : function(e)
37938 //Roo.log('listkeypress');
37939 // scroll to first matching element based on key pres..
37940 if (e.isSpecialKey()) {
37943 var k = String.fromCharCode(e.getKey()).toUpperCase();
37946 var csel = this.view.getSelectedNodes();
37947 var cselitem = false;
37949 var ix = this.view.indexOf(csel[0]);
37950 cselitem = this.store.getAt(ix);
37951 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
37957 this.store.each(function(v) {
37959 // start at existing selection.
37960 if (cselitem.id == v.id) {
37966 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
37967 match = this.store.indexOf(v);
37972 if (match === false) {
37973 return true; // no more action?
37976 this.view.select(match);
37977 var sn = Roo.get(this.view.getSelectedNodes()[0])
37978 sn.scrollIntoView(sn.dom.parentNode, false);
37982 * @cfg {Boolean} grow
37986 * @cfg {Number} growMin
37990 * @cfg {Number} growMax
37999 * Ext JS Library 1.1.1
38000 * Copyright(c) 2006-2007, Ext JS, LLC.
38002 * Originally Released Under LGPL - original licence link has changed is not relivant.
38005 * <script type="text/javascript">
38008 * @class Roo.form.Checkbox
38009 * @extends Roo.form.Field
38010 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38012 * Creates a new Checkbox
38013 * @param {Object} config Configuration options
38015 Roo.form.Checkbox = function(config){
38016 Roo.form.Checkbox.superclass.constructor.call(this, config);
38020 * Fires when the checkbox is checked or unchecked.
38021 * @param {Roo.form.Checkbox} this This checkbox
38022 * @param {Boolean} checked The new checked value
38028 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38030 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38032 focusClass : undefined,
38034 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38036 fieldClass: "x-form-field",
38038 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38042 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38043 * {tag: "input", type: "checkbox", autocomplete: "off"})
38045 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38047 * @cfg {String} boxLabel The text that appears beside the checkbox
38051 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38055 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38057 valueOff: '0', // value when not checked..
38059 actionMode : 'viewEl',
38062 itemCls : 'x-menu-check-item x-form-item',
38063 groupClass : 'x-menu-group-item',
38064 inputType : 'hidden',
38067 inSetChecked: false, // check that we are not calling self...
38069 inputElement: false, // real input element?
38070 basedOn: false, // ????
38072 isFormField: true, // not sure where this is needed!!!!
38074 onResize : function(){
38075 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38076 if(!this.boxLabel){
38077 this.el.alignTo(this.wrap, 'c-c');
38081 initEvents : function(){
38082 Roo.form.Checkbox.superclass.initEvents.call(this);
38083 this.el.on("click", this.onClick, this);
38084 this.el.on("change", this.onClick, this);
38088 getResizeEl : function(){
38092 getPositionEl : function(){
38097 onRender : function(ct, position){
38098 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38100 if(this.inputValue !== undefined){
38101 this.el.dom.value = this.inputValue;
38104 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38105 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38106 var viewEl = this.wrap.createChild({
38107 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38108 this.viewEl = viewEl;
38109 this.wrap.on('click', this.onClick, this);
38111 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38112 this.el.on('propertychange', this.setFromHidden, this); //ie
38117 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38118 // viewEl.on('click', this.onClick, this);
38120 //if(this.checked){
38121 this.setChecked(this.checked);
38123 //this.checked = this.el.dom;
38129 initValue : Roo.emptyFn,
38132 * Returns the checked state of the checkbox.
38133 * @return {Boolean} True if checked, else false
38135 getValue : function(){
38137 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38139 return this.valueOff;
38144 onClick : function(){
38145 this.setChecked(!this.checked);
38147 //if(this.el.dom.checked != this.checked){
38148 // this.setValue(this.el.dom.checked);
38153 * Sets the checked state of the checkbox.
38154 * On is always based on a string comparison between inputValue and the param.
38155 * @param {Boolean/String} value - the value to set
38156 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38158 setValue : function(v,suppressEvent){
38161 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38162 //if(this.el && this.el.dom){
38163 // this.el.dom.checked = this.checked;
38164 // this.el.dom.defaultChecked = this.checked;
38166 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38167 //this.fireEvent("check", this, this.checked);
38170 setChecked : function(state,suppressEvent)
38172 if (this.inSetChecked) {
38173 this.checked = state;
38179 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38181 this.checked = state;
38182 if(suppressEvent !== true){
38183 this.fireEvent('check', this, state);
38185 this.inSetChecked = true;
38186 this.el.dom.value = state ? this.inputValue : this.valueOff;
38187 this.inSetChecked = false;
38190 // handle setting of hidden value by some other method!!?!?
38191 setFromHidden: function()
38196 //console.log("SET FROM HIDDEN");
38197 //alert('setFrom hidden');
38198 this.setValue(this.el.dom.value);
38201 onDestroy : function()
38204 Roo.get(this.viewEl).remove();
38207 Roo.form.Checkbox.superclass.onDestroy.call(this);
38212 * Ext JS Library 1.1.1
38213 * Copyright(c) 2006-2007, Ext JS, LLC.
38215 * Originally Released Under LGPL - original licence link has changed is not relivant.
38218 * <script type="text/javascript">
38222 * @class Roo.form.Radio
38223 * @extends Roo.form.Checkbox
38224 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38225 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38227 * Creates a new Radio
38228 * @param {Object} config Configuration options
38230 Roo.form.Radio = function(){
38231 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38233 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38234 inputType: 'radio',
38237 * If this radio is part of a group, it will return the selected value
38240 getGroupValue : function(){
38241 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38243 });//<script type="text/javascript">
38246 * Ext JS Library 1.1.1
38247 * Copyright(c) 2006-2007, Ext JS, LLC.
38248 * licensing@extjs.com
38250 * http://www.extjs.com/license
38256 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38257 * - IE ? - no idea how much works there.
38265 * @class Ext.form.HtmlEditor
38266 * @extends Ext.form.Field
38267 * Provides a lightweight HTML Editor component.
38268 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38270 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38271 * supported by this editor.</b><br/><br/>
38272 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38273 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38275 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38277 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38281 * @cfg {String} createLinkText The default text for the create link prompt
38283 createLinkText : 'Please enter the URL for the link:',
38285 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38287 defaultLinkValue : 'http:/'+'/',
38293 // private properties
38294 validationEvent : false,
38296 initialized : false,
38298 sourceEditMode : false,
38299 onFocus : Roo.emptyFn,
38301 hideMode:'offsets',
38302 defaultAutoCreate : {
38304 style:"width:500px;height:300px;",
38305 autocomplete: "off"
38309 initComponent : function(){
38312 * @event initialize
38313 * Fires when the editor is fully initialized (including the iframe)
38314 * @param {HtmlEditor} this
38319 * Fires when the editor is first receives the focus. Any insertion must wait
38320 * until after this event.
38321 * @param {HtmlEditor} this
38325 * @event beforesync
38326 * Fires before the textarea is updated with content from the editor iframe. Return false
38327 * to cancel the sync.
38328 * @param {HtmlEditor} this
38329 * @param {String} html
38333 * @event beforepush
38334 * Fires before the iframe editor is updated with content from the textarea. Return false
38335 * to cancel the push.
38336 * @param {HtmlEditor} this
38337 * @param {String} html
38342 * Fires when the textarea is updated with content from the editor iframe.
38343 * @param {HtmlEditor} this
38344 * @param {String} html
38349 * Fires when the iframe editor is updated with content from the textarea.
38350 * @param {HtmlEditor} this
38351 * @param {String} html
38355 * @event editmodechange
38356 * Fires when the editor switches edit modes
38357 * @param {HtmlEditor} this
38358 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38360 editmodechange: true,
38362 * @event editorevent
38363 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38364 * @param {HtmlEditor} this
38371 * Protected method that will not generally be called directly. It
38372 * is called when the editor creates its toolbar. Override this method if you need to
38373 * add custom toolbar buttons.
38374 * @param {HtmlEditor} editor
38376 createToolbar : function(editor){
38377 if (!editor.toolbars || !editor.toolbars.length) {
38378 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38381 for (var i =0 ; i < editor.toolbars.length;i++) {
38382 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38383 editor.toolbars[i].init(editor);
38390 * Protected method that will not generally be called directly. It
38391 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38392 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38394 getDocMarkup : function(){
38395 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38399 onRender : function(ct, position){
38400 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38401 this.el.dom.style.border = '0 none';
38402 this.el.dom.setAttribute('tabIndex', -1);
38403 this.el.addClass('x-hidden');
38404 if(Roo.isIE){ // fix IE 1px bogus margin
38405 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38407 this.wrap = this.el.wrap({
38408 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38411 this.frameId = Roo.id();
38412 this.createToolbar(this);
38419 var iframe = this.wrap.createChild({
38422 name: this.frameId,
38423 frameBorder : 'no',
38424 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38427 // console.log(iframe);
38428 //this.wrap.dom.appendChild(iframe);
38430 this.iframe = iframe.dom;
38432 this.assignDocWin();
38434 this.doc.designMode = 'on';
38437 this.doc.write(this.getDocMarkup());
38441 var task = { // must defer to wait for browser to be ready
38443 //console.log("run task?" + this.doc.readyState);
38444 this.assignDocWin();
38445 if(this.doc.body || this.doc.readyState == 'complete'){
38447 this.doc.designMode="on";
38451 Roo.TaskMgr.stop(task);
38452 this.initEditor.defer(10, this);
38459 Roo.TaskMgr.start(task);
38462 this.setSize(this.el.getSize());
38467 onResize : function(w, h){
38468 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38469 if(this.el && this.iframe){
38470 if(typeof w == 'number'){
38471 var aw = w - this.wrap.getFrameWidth('lr');
38472 this.el.setWidth(this.adjustWidth('textarea', aw));
38473 this.iframe.style.width = aw + 'px';
38475 if(typeof h == 'number'){
38477 for (var i =0; i < this.toolbars.length;i++) {
38478 // fixme - ask toolbars for heights?
38479 tbh += this.toolbars[i].tb.el.getHeight();
38485 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38486 this.el.setHeight(this.adjustWidth('textarea', ah));
38487 this.iframe.style.height = ah + 'px';
38489 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38496 * Toggles the editor between standard and source edit mode.
38497 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38499 toggleSourceEdit : function(sourceEditMode){
38501 this.sourceEditMode = sourceEditMode === true;
38503 if(this.sourceEditMode){
38506 this.iframe.className = 'x-hidden';
38507 this.el.removeClass('x-hidden');
38508 this.el.dom.removeAttribute('tabIndex');
38513 this.iframe.className = '';
38514 this.el.addClass('x-hidden');
38515 this.el.dom.setAttribute('tabIndex', -1);
38518 this.setSize(this.wrap.getSize());
38519 this.fireEvent('editmodechange', this, this.sourceEditMode);
38522 // private used internally
38523 createLink : function(){
38524 var url = prompt(this.createLinkText, this.defaultLinkValue);
38525 if(url && url != 'http:/'+'/'){
38526 this.relayCmd('createlink', url);
38530 // private (for BoxComponent)
38531 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38533 // private (for BoxComponent)
38534 getResizeEl : function(){
38538 // private (for BoxComponent)
38539 getPositionEl : function(){
38544 initEvents : function(){
38545 this.originalValue = this.getValue();
38549 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38552 markInvalid : Roo.emptyFn,
38554 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38557 clearInvalid : Roo.emptyFn,
38559 setValue : function(v){
38560 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38565 * Protected method that will not generally be called directly. If you need/want
38566 * custom HTML cleanup, this is the method you should override.
38567 * @param {String} html The HTML to be cleaned
38568 * return {String} The cleaned HTML
38570 cleanHtml : function(html){
38571 html = String(html);
38572 if(html.length > 5){
38573 if(Roo.isSafari){ // strip safari nonsense
38574 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38577 if(html == ' '){
38584 * Protected method that will not generally be called directly. Syncs the contents
38585 * of the editor iframe with the textarea.
38587 syncValue : function(){
38588 if(this.initialized){
38589 var bd = (this.doc.body || this.doc.documentElement);
38590 var html = bd.innerHTML;
38592 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38593 var m = bs.match(/text-align:(.*?);/i);
38595 html = '<div style="'+m[0]+'">' + html + '</div>';
38598 html = this.cleanHtml(html);
38599 if(this.fireEvent('beforesync', this, html) !== false){
38600 this.el.dom.value = html;
38601 this.fireEvent('sync', this, html);
38607 * Protected method that will not generally be called directly. Pushes the value of the textarea
38608 * into the iframe editor.
38610 pushValue : function(){
38611 if(this.initialized){
38612 var v = this.el.dom.value;
38616 if(this.fireEvent('beforepush', this, v) !== false){
38617 (this.doc.body || this.doc.documentElement).innerHTML = v;
38618 this.fireEvent('push', this, v);
38624 deferFocus : function(){
38625 this.focus.defer(10, this);
38629 focus : function(){
38630 if(this.win && !this.sourceEditMode){
38637 assignDocWin: function()
38639 var iframe = this.iframe;
38642 this.doc = iframe.contentWindow.document;
38643 this.win = iframe.contentWindow;
38645 if (!Roo.get(this.frameId)) {
38648 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38649 this.win = Roo.get(this.frameId).dom.contentWindow;
38654 initEditor : function(){
38655 //console.log("INIT EDITOR");
38656 this.assignDocWin();
38660 this.doc.designMode="on";
38662 this.doc.write(this.getDocMarkup());
38665 var dbody = (this.doc.body || this.doc.documentElement);
38666 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38667 // this copies styles from the containing element into thsi one..
38668 // not sure why we need all of this..
38669 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38670 ss['background-attachment'] = 'fixed'; // w3c
38671 dbody.bgProperties = 'fixed'; // ie
38672 Roo.DomHelper.applyStyles(dbody, ss);
38673 Roo.EventManager.on(this.doc, {
38674 'mousedown': this.onEditorEvent,
38675 'dblclick': this.onEditorEvent,
38676 'click': this.onEditorEvent,
38677 'keyup': this.onEditorEvent,
38682 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38684 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38685 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38687 this.initialized = true;
38689 this.fireEvent('initialize', this);
38694 onDestroy : function(){
38700 for (var i =0; i < this.toolbars.length;i++) {
38701 // fixme - ask toolbars for heights?
38702 this.toolbars[i].onDestroy();
38705 this.wrap.dom.innerHTML = '';
38706 this.wrap.remove();
38711 onFirstFocus : function(){
38713 this.assignDocWin();
38716 this.activated = true;
38717 for (var i =0; i < this.toolbars.length;i++) {
38718 this.toolbars[i].onFirstFocus();
38721 if(Roo.isGecko){ // prevent silly gecko errors
38723 var s = this.win.getSelection();
38724 if(!s.focusNode || s.focusNode.nodeType != 3){
38725 var r = s.getRangeAt(0);
38726 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38731 this.execCmd('useCSS', true);
38732 this.execCmd('styleWithCSS', false);
38735 this.fireEvent('activate', this);
38739 adjustFont: function(btn){
38740 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38741 //if(Roo.isSafari){ // safari
38744 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38745 if(Roo.isSafari){ // safari
38746 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38747 v = (v < 10) ? 10 : v;
38748 v = (v > 48) ? 48 : v;
38749 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38754 v = Math.max(1, v+adjust);
38756 this.execCmd('FontSize', v );
38759 onEditorEvent : function(e){
38760 this.fireEvent('editorevent', this, e);
38761 // this.updateToolbar();
38765 insertTag : function(tg)
38767 // could be a bit smarter... -> wrap the current selected tRoo..
38769 this.execCmd("formatblock", tg);
38773 insertText : function(txt)
38777 range = this.createRange();
38778 range.deleteContents();
38779 //alert(Sender.getAttribute('label'));
38781 range.insertNode(this.doc.createTextNode(txt));
38785 relayBtnCmd : function(btn){
38786 this.relayCmd(btn.cmd);
38790 * Executes a Midas editor command on the editor document and performs necessary focus and
38791 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38792 * @param {String} cmd The Midas command
38793 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38795 relayCmd : function(cmd, value){
38797 this.execCmd(cmd, value);
38798 this.fireEvent('editorevent', this);
38799 //this.updateToolbar();
38804 * Executes a Midas editor command directly on the editor document.
38805 * For visual commands, you should use {@link #relayCmd} instead.
38806 * <b>This should only be called after the editor is initialized.</b>
38807 * @param {String} cmd The Midas command
38808 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38810 execCmd : function(cmd, value){
38811 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38817 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38819 * @param {String} text
38821 insertAtCursor : function(text){
38822 if(!this.activated){
38827 var r = this.doc.selection.createRange();
38834 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38836 this.execCmd('InsertHTML', text);
38841 mozKeyPress : function(e){
38843 var c = e.getCharCode(), cmd;
38846 c = String.fromCharCode(c).toLowerCase();
38857 this.cleanUpPaste.defer(100, this);
38865 e.preventDefault();
38873 fixKeys : function(){ // load time branching for fastest keydown performance
38875 return function(e){
38876 var k = e.getKey(), r;
38879 r = this.doc.selection.createRange();
38882 r.pasteHTML('    ');
38889 r = this.doc.selection.createRange();
38891 var target = r.parentElement();
38892 if(!target || target.tagName.toLowerCase() != 'li'){
38894 r.pasteHTML('<br />');
38900 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38901 this.cleanUpPaste.defer(100, this);
38907 }else if(Roo.isOpera){
38908 return function(e){
38909 var k = e.getKey();
38913 this.execCmd('InsertHTML','    ');
38916 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38917 this.cleanUpPaste.defer(100, this);
38922 }else if(Roo.isSafari){
38923 return function(e){
38924 var k = e.getKey();
38928 this.execCmd('InsertText','\t');
38932 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38933 this.cleanUpPaste.defer(100, this);
38941 getAllAncestors: function()
38943 var p = this.getSelectedNode();
38946 a.push(p); // push blank onto stack..
38947 p = this.getParentElement();
38951 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38955 a.push(this.doc.body);
38959 lastSelNode : false,
38962 getSelection : function()
38964 this.assignDocWin();
38965 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38968 getSelectedNode: function()
38970 // this may only work on Gecko!!!
38972 // should we cache this!!!!
38977 var range = this.createRange(this.getSelection());
38980 var parent = range.parentElement();
38982 var testRange = range.duplicate();
38983 testRange.moveToElementText(parent);
38984 if (testRange.inRange(range)) {
38987 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38990 parent = parent.parentElement;
38996 var ar = range.endContainer.childNodes;
38998 ar = range.commonAncestorContainer.childNodes;
38999 //alert(ar.length);
39002 var other_nodes = [];
39003 var has_other_nodes = false;
39004 for (var i=0;i<ar.length;i++) {
39005 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39008 // fullly contained node.
39010 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39015 // probably selected..
39016 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39017 other_nodes.push(ar[i]);
39020 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39025 has_other_nodes = true;
39027 if (!nodes.length && other_nodes.length) {
39028 nodes= other_nodes;
39030 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39036 createRange: function(sel)
39038 // this has strange effects when using with
39039 // top toolbar - not sure if it's a great idea.
39040 //this.editor.contentWindow.focus();
39041 if (typeof sel != "undefined") {
39043 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39045 return this.doc.createRange();
39048 return this.doc.createRange();
39051 getParentElement: function()
39054 this.assignDocWin();
39055 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39057 var range = this.createRange(sel);
39060 var p = range.commonAncestorContainer;
39061 while (p.nodeType == 3) { // text node
39073 // BC Hacks - cause I cant work out what i was trying to do..
39074 rangeIntersectsNode : function(range, node)
39076 var nodeRange = node.ownerDocument.createRange();
39078 nodeRange.selectNode(node);
39081 nodeRange.selectNodeContents(node);
39084 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39085 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39087 rangeCompareNode : function(range, node) {
39088 var nodeRange = node.ownerDocument.createRange();
39090 nodeRange.selectNode(node);
39092 nodeRange.selectNodeContents(node);
39094 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39095 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39097 if (nodeIsBefore && !nodeIsAfter)
39099 if (!nodeIsBefore && nodeIsAfter)
39101 if (nodeIsBefore && nodeIsAfter)
39107 // private? - in a new class?
39108 cleanUpPaste : function()
39110 // cleans up the whole document..
39111 // console.log('cleanuppaste');
39112 this.cleanUpChildren(this.doc.body)
39116 cleanUpChildren : function (n)
39118 if (!n.childNodes.length) {
39121 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39122 this.cleanUpChild(n.childNodes[i]);
39129 cleanUpChild : function (node)
39131 //console.log(node);
39132 if (node.nodeName == "#text") {
39133 // clean up silly Windows -- stuff?
39136 if (node.nodeName == "#comment") {
39137 node.parentNode.removeChild(node);
39138 // clean up silly Windows -- stuff?
39142 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39144 node.parentNode.removeChild(node);
39148 if (!node.attributes || !node.attributes.length) {
39149 this.cleanUpChildren(node);
39153 function cleanAttr(n,v)
39156 if (v.match(/^\./) || v.match(/^\//)) {
39159 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39162 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39163 node.removeAttribute(n);
39167 function cleanStyle(n,v)
39169 if (v.match(/expression/)) { //XSS?? should we even bother..
39170 node.removeAttribute(n);
39175 var parts = v.split(/;/);
39176 Roo.each(parts, function(p) {
39177 p = p.replace(/\s+/g,'');
39181 var l = p.split(':').shift().replace(/\s+/g,'');
39183 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39184 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39185 node.removeAttribute(n);
39194 for (var i = node.attributes.length-1; i > -1 ; i--) {
39195 var a = node.attributes[i];
39197 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39198 node.removeAttribute(a.name);
39201 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39202 cleanAttr(a.name,a.value); // fixme..
39205 if (a.name == 'style') {
39206 cleanStyle(a.name,a.value);
39208 /// clean up MS crap..
39209 if (a.name == 'class') {
39210 if (a.value.match(/^Mso/)) {
39211 node.className = '';
39221 this.cleanUpChildren(node);
39227 // hide stuff that is not compatible
39241 * @event specialkey
39245 * @cfg {String} fieldClass @hide
39248 * @cfg {String} focusClass @hide
39251 * @cfg {String} autoCreate @hide
39254 * @cfg {String} inputType @hide
39257 * @cfg {String} invalidClass @hide
39260 * @cfg {String} invalidText @hide
39263 * @cfg {String} msgFx @hide
39266 * @cfg {String} validateOnBlur @hide
39270 Roo.form.HtmlEditor.white = [
39271 'area', 'br', 'img', 'input', 'hr', 'wbr',
39273 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39274 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39275 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39276 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39277 'table', 'ul', 'xmp',
39279 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39282 'dir', 'menu', 'ol', 'ul', 'dl',
39288 Roo.form.HtmlEditor.black = [
39289 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39291 'base', 'basefont', 'bgsound', 'blink', 'body',
39292 'frame', 'frameset', 'head', 'html', 'ilayer',
39293 'iframe', 'layer', 'link', 'meta', 'object',
39294 'script', 'style' ,'title', 'xml' // clean later..
39296 Roo.form.HtmlEditor.clean = [
39297 'script', 'style', 'title', 'xml'
39302 Roo.form.HtmlEditor.ablack = [
39306 Roo.form.HtmlEditor.aclean = [
39307 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39311 Roo.form.HtmlEditor.pwhite= [
39312 'http', 'https', 'mailto'
39315 Roo.form.HtmlEditor.cwhite= [
39320 // <script type="text/javascript">
39323 * Ext JS Library 1.1.1
39324 * Copyright(c) 2006-2007, Ext JS, LLC.
39330 * @class Roo.form.HtmlEditorToolbar1
39335 new Roo.form.HtmlEditor({
39338 new Roo.form.HtmlEditorToolbar1({
39339 disable : { fonts: 1 , format: 1, ..., ... , ...],
39345 * @cfg {Object} disable List of elements to disable..
39346 * @cfg {Array} btns List of additional buttons.
39350 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39353 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39356 Roo.apply(this, config);
39357 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39358 // dont call parent... till later.
39361 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39369 * @cfg {Object} disable List of toolbar elements to disable
39374 * @cfg {Array} fontFamilies An array of available font families
39392 // "á" , ?? a acute?
39397 "°" // , // degrees
39399 // "é" , // e ecute
39400 // "ú" , // u ecute?
39403 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39404 "input:submit", "input:button", "select", "textarea", "label" ],
39407 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39409 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39412 * @cfg {String} defaultFont default font to use.
39414 defaultFont: 'tahoma',
39416 fontSelect : false,
39419 formatCombo : false,
39421 init : function(editor)
39423 this.editor = editor;
39426 var fid = editor.frameId;
39428 function btn(id, toggle, handler){
39429 var xid = fid + '-'+ id ;
39433 cls : 'x-btn-icon x-edit-'+id,
39434 enableToggle:toggle !== false,
39435 scope: editor, // was editor...
39436 handler:handler||editor.relayBtnCmd,
39437 clickEvent:'mousedown',
39438 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39445 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39447 // stop form submits
39448 tb.el.on('click', function(e){
39449 e.preventDefault(); // what does this do?
39452 if(!this.disable.font && !Roo.isSafari){
39453 /* why no safari for fonts
39454 editor.fontSelect = tb.el.createChild({
39457 cls:'x-font-select',
39458 html: editor.createFontOptions()
39460 editor.fontSelect.on('change', function(){
39461 var font = editor.fontSelect.dom.value;
39462 editor.relayCmd('fontname', font);
39463 editor.deferFocus();
39466 editor.fontSelect.dom,
39471 if(!this.disable.formats){
39472 this.formatCombo = new Roo.form.ComboBox({
39473 store: new Roo.data.SimpleStore({
39476 data : this.formats // from states.js
39479 //autoCreate : {tag: "div", size: "20"},
39480 displayField:'tag',
39484 triggerAction: 'all',
39485 emptyText:'Add tag',
39486 selectOnFocus:true,
39489 'select': function(c, r, i) {
39490 editor.insertTag(r.get('tag'));
39496 tb.addField(this.formatCombo);
39500 if(!this.disable.format){
39507 if(!this.disable.fontSize){
39512 btn('increasefontsize', false, editor.adjustFont),
39513 btn('decreasefontsize', false, editor.adjustFont)
39518 if(this.disable.colors){
39521 id:editor.frameId +'-forecolor',
39522 cls:'x-btn-icon x-edit-forecolor',
39523 clickEvent:'mousedown',
39524 tooltip: this.buttonTips['forecolor'] || undefined,
39526 menu : new Roo.menu.ColorMenu({
39527 allowReselect: true,
39528 focus: Roo.emptyFn,
39531 selectHandler: function(cp, color){
39532 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39533 editor.deferFocus();
39536 clickEvent:'mousedown'
39539 id:editor.frameId +'backcolor',
39540 cls:'x-btn-icon x-edit-backcolor',
39541 clickEvent:'mousedown',
39542 tooltip: this.buttonTips['backcolor'] || undefined,
39544 menu : new Roo.menu.ColorMenu({
39545 focus: Roo.emptyFn,
39548 allowReselect: true,
39549 selectHandler: function(cp, color){
39551 editor.execCmd('useCSS', false);
39552 editor.execCmd('hilitecolor', color);
39553 editor.execCmd('useCSS', true);
39554 editor.deferFocus();
39556 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39557 Roo.isSafari || Roo.isIE ? '#'+color : color);
39558 editor.deferFocus();
39562 clickEvent:'mousedown'
39567 // now add all the items...
39570 if(!this.disable.alignments){
39573 btn('justifyleft'),
39574 btn('justifycenter'),
39575 btn('justifyright')
39579 //if(!Roo.isSafari){
39580 if(!this.disable.links){
39583 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39587 if(!this.disable.lists){
39590 btn('insertorderedlist'),
39591 btn('insertunorderedlist')
39594 if(!this.disable.sourceEdit){
39597 btn('sourceedit', true, function(btn){
39598 this.toggleSourceEdit(btn.pressed);
39605 // special menu.. - needs to be tidied up..
39606 if (!this.disable.special) {
39609 cls: 'x-edit-none',
39614 for (var i =0; i < this.specialChars.length; i++) {
39615 smenu.menu.items.push({
39617 html: this.specialChars[i],
39618 handler: function(a,b) {
39619 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39632 for(var i =0; i< this.btns.length;i++) {
39633 var b = this.btns[i];
39634 b.cls = 'x-edit-none';
39643 // disable everything...
39645 this.tb.items.each(function(item){
39646 if(item.id != editor.frameId+ '-sourceedit'){
39650 this.rendered = true;
39652 // the all the btns;
39653 editor.on('editorevent', this.updateToolbar, this);
39654 // other toolbars need to implement this..
39655 //editor.on('editmodechange', this.updateToolbar, this);
39661 * Protected method that will not generally be called directly. It triggers
39662 * a toolbar update by reading the markup state of the current selection in the editor.
39664 updateToolbar: function(){
39666 if(!this.editor.activated){
39667 this.editor.onFirstFocus();
39671 var btns = this.tb.items.map,
39672 doc = this.editor.doc,
39673 frameId = this.editor.frameId;
39675 if(!this.disable.font && !Roo.isSafari){
39677 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39678 if(name != this.fontSelect.dom.value){
39679 this.fontSelect.dom.value = name;
39683 if(!this.disable.format){
39684 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39685 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39686 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39688 if(!this.disable.alignments){
39689 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39690 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39691 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39693 if(!Roo.isSafari && !this.disable.lists){
39694 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39695 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39698 var ans = this.editor.getAllAncestors();
39699 if (this.formatCombo) {
39702 var store = this.formatCombo.store;
39703 this.formatCombo.setValue("");
39704 for (var i =0; i < ans.length;i++) {
39705 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39707 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39715 // hides menus... - so this cant be on a menu...
39716 Roo.menu.MenuMgr.hideAll();
39718 //this.editorsyncValue();
39722 createFontOptions : function(){
39723 var buf = [], fs = this.fontFamilies, ff, lc;
39724 for(var i = 0, len = fs.length; i< len; i++){
39726 lc = ff.toLowerCase();
39728 '<option value="',lc,'" style="font-family:',ff,';"',
39729 (this.defaultFont == lc ? ' selected="true">' : '>'),
39734 return buf.join('');
39737 toggleSourceEdit : function(sourceEditMode){
39738 if(sourceEditMode === undefined){
39739 sourceEditMode = !this.sourceEditMode;
39741 this.sourceEditMode = sourceEditMode === true;
39742 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39743 // just toggle the button?
39744 if(btn.pressed !== this.editor.sourceEditMode){
39745 btn.toggle(this.editor.sourceEditMode);
39749 if(this.sourceEditMode){
39750 this.tb.items.each(function(item){
39751 if(item.cmd != 'sourceedit'){
39757 if(this.initialized){
39758 this.tb.items.each(function(item){
39764 // tell the editor that it's been pressed..
39765 this.editor.toggleSourceEdit(sourceEditMode);
39769 * Object collection of toolbar tooltips for the buttons in the editor. The key
39770 * is the command id associated with that button and the value is a valid QuickTips object.
39775 title: 'Bold (Ctrl+B)',
39776 text: 'Make the selected text bold.',
39777 cls: 'x-html-editor-tip'
39780 title: 'Italic (Ctrl+I)',
39781 text: 'Make the selected text italic.',
39782 cls: 'x-html-editor-tip'
39790 title: 'Bold (Ctrl+B)',
39791 text: 'Make the selected text bold.',
39792 cls: 'x-html-editor-tip'
39795 title: 'Italic (Ctrl+I)',
39796 text: 'Make the selected text italic.',
39797 cls: 'x-html-editor-tip'
39800 title: 'Underline (Ctrl+U)',
39801 text: 'Underline the selected text.',
39802 cls: 'x-html-editor-tip'
39804 increasefontsize : {
39805 title: 'Grow Text',
39806 text: 'Increase the font size.',
39807 cls: 'x-html-editor-tip'
39809 decreasefontsize : {
39810 title: 'Shrink Text',
39811 text: 'Decrease the font size.',
39812 cls: 'x-html-editor-tip'
39815 title: 'Text Highlight Color',
39816 text: 'Change the background color of the selected text.',
39817 cls: 'x-html-editor-tip'
39820 title: 'Font Color',
39821 text: 'Change the color of the selected text.',
39822 cls: 'x-html-editor-tip'
39825 title: 'Align Text Left',
39826 text: 'Align text to the left.',
39827 cls: 'x-html-editor-tip'
39830 title: 'Center Text',
39831 text: 'Center text in the editor.',
39832 cls: 'x-html-editor-tip'
39835 title: 'Align Text Right',
39836 text: 'Align text to the right.',
39837 cls: 'x-html-editor-tip'
39839 insertunorderedlist : {
39840 title: 'Bullet List',
39841 text: 'Start a bulleted list.',
39842 cls: 'x-html-editor-tip'
39844 insertorderedlist : {
39845 title: 'Numbered List',
39846 text: 'Start a numbered list.',
39847 cls: 'x-html-editor-tip'
39850 title: 'Hyperlink',
39851 text: 'Make the selected text a hyperlink.',
39852 cls: 'x-html-editor-tip'
39855 title: 'Source Edit',
39856 text: 'Switch to source editing mode.',
39857 cls: 'x-html-editor-tip'
39861 onDestroy : function(){
39864 this.tb.items.each(function(item){
39866 item.menu.removeAll();
39868 item.menu.el.destroy();
39876 onFirstFocus: function() {
39877 this.tb.items.each(function(item){
39886 // <script type="text/javascript">
39889 * Ext JS Library 1.1.1
39890 * Copyright(c) 2006-2007, Ext JS, LLC.
39897 * @class Roo.form.HtmlEditor.ToolbarContext
39902 new Roo.form.HtmlEditor({
39905 new Roo.form.HtmlEditor.ToolbarStandard(),
39906 new Roo.form.HtmlEditor.ToolbarContext()
39911 * @config : {Object} disable List of elements to disable.. (not done yet.)
39916 Roo.form.HtmlEditor.ToolbarContext = function(config)
39919 Roo.apply(this, config);
39920 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39921 // dont call parent... till later.
39923 Roo.form.HtmlEditor.ToolbarContext.types = {
39935 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39997 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40002 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40066 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40074 * @cfg {Object} disable List of toolbar elements to disable
40083 init : function(editor)
40085 this.editor = editor;
40088 var fid = editor.frameId;
40090 function btn(id, toggle, handler){
40091 var xid = fid + '-'+ id ;
40095 cls : 'x-btn-icon x-edit-'+id,
40096 enableToggle:toggle !== false,
40097 scope: editor, // was editor...
40098 handler:handler||editor.relayBtnCmd,
40099 clickEvent:'mousedown',
40100 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40104 // create a new element.
40105 var wdiv = editor.wrap.createChild({
40107 }, editor.wrap.dom.firstChild.nextSibling, true);
40109 // can we do this more than once??
40111 // stop form submits
40114 // disable everything...
40115 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40116 this.toolbars = {};
40118 for (var i in ty) {
40120 this.toolbars[i] = this.buildToolbar(ty[i],i);
40122 this.tb = this.toolbars.BODY;
40126 this.rendered = true;
40128 // the all the btns;
40129 editor.on('editorevent', this.updateToolbar, this);
40130 // other toolbars need to implement this..
40131 //editor.on('editmodechange', this.updateToolbar, this);
40137 * Protected method that will not generally be called directly. It triggers
40138 * a toolbar update by reading the markup state of the current selection in the editor.
40140 updateToolbar: function(){
40142 if(!this.editor.activated){
40143 this.editor.onFirstFocus();
40148 var ans = this.editor.getAllAncestors();
40151 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40152 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40153 sel = sel ? sel : this.editor.doc.body;
40154 sel = sel.tagName.length ? sel : this.editor.doc.body;
40155 var tn = sel.tagName.toUpperCase();
40156 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40157 tn = sel.tagName.toUpperCase();
40158 if (this.tb.name == tn) {
40159 return; // no change
40162 ///console.log("show: " + tn);
40163 this.tb = this.toolbars[tn];
40165 this.tb.fields.each(function(e) {
40166 e.setValue(sel.getAttribute(e.name));
40168 this.tb.selectedNode = sel;
40171 Roo.menu.MenuMgr.hideAll();
40173 //this.editorsyncValue();
40178 onDestroy : function(){
40181 this.tb.items.each(function(item){
40183 item.menu.removeAll();
40185 item.menu.el.destroy();
40193 onFirstFocus: function() {
40194 // need to do this for all the toolbars..
40195 this.tb.items.each(function(item){
40199 buildToolbar: function(tlist, nm)
40201 var editor = this.editor;
40202 // create a new element.
40203 var wdiv = editor.wrap.createChild({
40205 }, editor.wrap.dom.firstChild.nextSibling, true);
40208 var tb = new Roo.Toolbar(wdiv);
40209 tb.add(nm+ ": ");
40210 for (var i in tlist) {
40211 var item = tlist[i];
40212 tb.add(item.title + ": ");
40217 tb.addField( new Roo.form.ComboBox({
40218 store: new Roo.data.SimpleStore({
40221 data : item.opts // from states.js
40224 displayField:'val',
40228 triggerAction: 'all',
40229 emptyText:'Select',
40230 selectOnFocus:true,
40231 width: item.width ? item.width : 130,
40233 'select': function(c, r, i) {
40234 tb.selectedNode.setAttribute(c.name, r.get('val'));
40245 tb.addField( new Roo.form.TextField({
40248 //allowBlank:false,
40253 tb.addField( new Roo.form.TextField({
40259 'change' : function(f, nv, ov) {
40260 tb.selectedNode.setAttribute(f.name, nv);
40266 tb.el.on('click', function(e){
40267 e.preventDefault(); // what does this do?
40269 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40272 // dont need to disable them... as they will get hidden
40289 * Ext JS Library 1.1.1
40290 * Copyright(c) 2006-2007, Ext JS, LLC.
40292 * Originally Released Under LGPL - original licence link has changed is not relivant.
40295 * <script type="text/javascript">
40299 * @class Roo.form.BasicForm
40300 * @extends Roo.util.Observable
40301 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40303 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40304 * @param {Object} config Configuration options
40306 Roo.form.BasicForm = function(el, config){
40307 this.allItems = [];
40308 this.childForms = [];
40309 Roo.apply(this, config);
40311 * The Roo.form.Field items in this form.
40312 * @type MixedCollection
40316 this.items = new Roo.util.MixedCollection(false, function(o){
40317 return o.id || (o.id = Roo.id());
40321 * @event beforeaction
40322 * Fires before any action is performed. Return false to cancel the action.
40323 * @param {Form} this
40324 * @param {Action} action The action to be performed
40326 beforeaction: true,
40328 * @event actionfailed
40329 * Fires when an action fails.
40330 * @param {Form} this
40331 * @param {Action} action The action that failed
40333 actionfailed : true,
40335 * @event actioncomplete
40336 * Fires when an action is completed.
40337 * @param {Form} this
40338 * @param {Action} action The action that completed
40340 actioncomplete : true
40345 Roo.form.BasicForm.superclass.constructor.call(this);
40348 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40350 * @cfg {String} method
40351 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40354 * @cfg {DataReader} reader
40355 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40356 * This is optional as there is built-in support for processing JSON.
40359 * @cfg {DataReader} errorReader
40360 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40361 * This is completely optional as there is built-in support for processing JSON.
40364 * @cfg {String} url
40365 * The URL to use for form actions if one isn't supplied in the action options.
40368 * @cfg {Boolean} fileUpload
40369 * Set to true if this form is a file upload.
40372 * @cfg {Object} baseParams
40373 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40376 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40381 activeAction : null,
40384 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40385 * or setValues() data instead of when the form was first created.
40387 trackResetOnLoad : false,
40391 * childForms - used for multi-tab forms
40394 childForms : false,
40397 * allItems - full list of fields.
40403 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40404 * element by passing it or its id or mask the form itself by passing in true.
40407 waitMsgTarget : undefined,
40410 initEl : function(el){
40411 this.el = Roo.get(el);
40412 this.id = this.el.id || Roo.id();
40413 this.el.on('submit', this.onSubmit, this);
40414 this.el.addClass('x-form');
40418 onSubmit : function(e){
40423 * Returns true if client-side validation on the form is successful.
40426 isValid : function(){
40428 this.items.each(function(f){
40437 * Returns true if any fields in this form have changed since their original load.
40440 isDirty : function(){
40442 this.items.each(function(f){
40452 * Performs a predefined action (submit or load) or custom actions you define on this form.
40453 * @param {String} actionName The name of the action type
40454 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40455 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40456 * accept other config options):
40458 Property Type Description
40459 ---------------- --------------- ----------------------------------------------------------------------------------
40460 url String The url for the action (defaults to the form's url)
40461 method String The form method to use (defaults to the form's method, or POST if not defined)
40462 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40463 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40464 validate the form on the client (defaults to false)
40466 * @return {BasicForm} this
40468 doAction : function(action, options){
40469 if(typeof action == 'string'){
40470 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40472 if(this.fireEvent('beforeaction', this, action) !== false){
40473 this.beforeAction(action);
40474 action.run.defer(100, action);
40480 * Shortcut to do a submit action.
40481 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40482 * @return {BasicForm} this
40484 submit : function(options){
40485 this.doAction('submit', options);
40490 * Shortcut to do a load action.
40491 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40492 * @return {BasicForm} this
40494 load : function(options){
40495 this.doAction('load', options);
40500 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40501 * @param {Record} record The record to edit
40502 * @return {BasicForm} this
40504 updateRecord : function(record){
40505 record.beginEdit();
40506 var fs = record.fields;
40507 fs.each(function(f){
40508 var field = this.findField(f.name);
40510 record.set(f.name, field.getValue());
40518 * Loads an Roo.data.Record into this form.
40519 * @param {Record} record The record to load
40520 * @return {BasicForm} this
40522 loadRecord : function(record){
40523 this.setValues(record.data);
40528 beforeAction : function(action){
40529 var o = action.options;
40531 if(this.waitMsgTarget === true){
40532 this.el.mask(o.waitMsg, 'x-mask-loading');
40533 }else if(this.waitMsgTarget){
40534 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40535 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
40537 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
40543 afterAction : function(action, success){
40544 this.activeAction = null;
40545 var o = action.options;
40547 if(this.waitMsgTarget === true){
40549 }else if(this.waitMsgTarget){
40550 this.waitMsgTarget.unmask();
40552 Roo.MessageBox.updateProgress(1);
40553 Roo.MessageBox.hide();
40560 Roo.callback(o.success, o.scope, [this, action]);
40561 this.fireEvent('actioncomplete', this, action);
40563 Roo.callback(o.failure, o.scope, [this, action]);
40564 this.fireEvent('actionfailed', this, action);
40569 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40570 * @param {String} id The value to search for
40573 findField : function(id){
40574 var field = this.items.get(id);
40576 this.items.each(function(f){
40577 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40583 return field || null;
40587 * Add a secondary form to this one,
40588 * Used to provide tabbed forms. One form is primary, with hidden values
40589 * which mirror the elements from the other forms.
40591 * @param {Roo.form.Form} form to add.
40594 addForm : function(form)
40597 if (this.childForms.indexOf(form) > -1) {
40601 this.childForms.push(form);
40603 Roo.each(form.allItems, function (fe) {
40605 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40606 if (this.findField(n)) { // already added..
40609 var add = new Roo.form.Hidden({
40612 add.render(this.el);
40619 * Mark fields in this form invalid in bulk.
40620 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40621 * @return {BasicForm} this
40623 markInvalid : function(errors){
40624 if(errors instanceof Array){
40625 for(var i = 0, len = errors.length; i < len; i++){
40626 var fieldError = errors[i];
40627 var f = this.findField(fieldError.id);
40629 f.markInvalid(fieldError.msg);
40635 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40636 field.markInvalid(errors[id]);
40640 Roo.each(this.childForms || [], function (f) {
40641 f.markInvalid(errors);
40648 * Set values for fields in this form in bulk.
40649 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40650 * @return {BasicForm} this
40652 setValues : function(values){
40653 if(values instanceof Array){ // array of objects
40654 for(var i = 0, len = values.length; i < len; i++){
40656 var f = this.findField(v.id);
40658 f.setValue(v.value);
40659 if(this.trackResetOnLoad){
40660 f.originalValue = f.getValue();
40664 }else{ // object hash
40667 if(typeof values[id] != 'function' && (field = this.findField(id))){
40669 if (field.setFromData &&
40670 field.valueField &&
40671 field.displayField &&
40672 // combos' with local stores can
40673 // be queried via setValue()
40674 // to set their value..
40675 (field.store && !field.store.isLocal)
40679 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40680 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40681 field.setFromData(sd);
40684 field.setValue(values[id]);
40688 if(this.trackResetOnLoad){
40689 field.originalValue = field.getValue();
40695 Roo.each(this.childForms || [], function (f) {
40696 f.setValues(values);
40703 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40704 * they are returned as an array.
40705 * @param {Boolean} asString
40708 getValues : function(asString){
40709 if (this.childForms) {
40710 // copy values from the child forms
40711 Roo.each(this.childForms, function (f) {
40712 this.setValues(f.getValues());
40718 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40719 if(asString === true){
40722 return Roo.urlDecode(fs);
40726 * Returns the fields in this form as an object with key/value pairs.
40727 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40730 getFieldValues : function()
40732 if (this.childForms) {
40733 // copy values from the child forms
40734 Roo.each(this.childForms, function (f) {
40735 this.setValues(f.getValues());
40740 this.items.each(function(f){
40741 if (!f.getName()) {
40744 var v = f.getValue();
40745 if ((typeof(v) == 'object') && f.getRawValue) {
40746 v = f.getRawValue() ; // dates..
40748 ret[f.getName()] = v;
40755 * Clears all invalid messages in this form.
40756 * @return {BasicForm} this
40758 clearInvalid : function(){
40759 this.items.each(function(f){
40763 Roo.each(this.childForms || [], function (f) {
40772 * Resets this form.
40773 * @return {BasicForm} this
40775 reset : function(){
40776 this.items.each(function(f){
40780 Roo.each(this.childForms || [], function (f) {
40789 * Add Roo.form components to this form.
40790 * @param {Field} field1
40791 * @param {Field} field2 (optional)
40792 * @param {Field} etc (optional)
40793 * @return {BasicForm} this
40796 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40802 * Removes a field from the items collection (does NOT remove its markup).
40803 * @param {Field} field
40804 * @return {BasicForm} this
40806 remove : function(field){
40807 this.items.remove(field);
40812 * Looks at the fields in this form, checks them for an id attribute,
40813 * and calls applyTo on the existing dom element with that id.
40814 * @return {BasicForm} this
40816 render : function(){
40817 this.items.each(function(f){
40818 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40826 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40827 * @param {Object} values
40828 * @return {BasicForm} this
40830 applyToFields : function(o){
40831 this.items.each(function(f){
40838 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40839 * @param {Object} values
40840 * @return {BasicForm} this
40842 applyIfToFields : function(o){
40843 this.items.each(function(f){
40851 Roo.BasicForm = Roo.form.BasicForm;/*
40853 * Ext JS Library 1.1.1
40854 * Copyright(c) 2006-2007, Ext JS, LLC.
40856 * Originally Released Under LGPL - original licence link has changed is not relivant.
40859 * <script type="text/javascript">
40863 * @class Roo.form.Form
40864 * @extends Roo.form.BasicForm
40865 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40867 * @param {Object} config Configuration options
40869 Roo.form.Form = function(config){
40871 if (config.items) {
40872 xitems = config.items;
40873 delete config.items;
40877 Roo.form.Form.superclass.constructor.call(this, null, config);
40878 this.url = this.url || this.action;
40880 this.root = new Roo.form.Layout(Roo.applyIf({
40884 this.active = this.root;
40886 * Array of all the buttons that have been added to this form via {@link addButton}
40890 this.allItems = [];
40893 * @event clientvalidation
40894 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40895 * @param {Form} this
40896 * @param {Boolean} valid true if the form has passed client-side validation
40898 clientvalidation: true,
40901 * Fires when the form is rendered
40902 * @param {Roo.form.Form} form
40907 if (this.progressUrl) {
40908 // push a hidden field onto the list of fields..
40912 name : 'UPLOAD_IDENTIFIER'
40917 Roo.each(xitems, this.addxtype, this);
40923 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40925 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40928 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40931 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40933 buttonAlign:'center',
40936 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40941 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40942 * This property cascades to child containers if not set.
40947 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40948 * fires a looping event with that state. This is required to bind buttons to the valid
40949 * state using the config value formBind:true on the button.
40951 monitorValid : false,
40954 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40959 * @cfg {String} progressUrl - Url to return progress data
40962 progressUrl : false,
40965 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40966 * fields are added and the column is closed. If no fields are passed the column remains open
40967 * until end() is called.
40968 * @param {Object} config The config to pass to the column
40969 * @param {Field} field1 (optional)
40970 * @param {Field} field2 (optional)
40971 * @param {Field} etc (optional)
40972 * @return Column The column container object
40974 column : function(c){
40975 var col = new Roo.form.Column(c);
40977 if(arguments.length > 1){ // duplicate code required because of Opera
40978 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40985 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40986 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40987 * until end() is called.
40988 * @param {Object} config The config to pass to the fieldset
40989 * @param {Field} field1 (optional)
40990 * @param {Field} field2 (optional)
40991 * @param {Field} etc (optional)
40992 * @return FieldSet The fieldset container object
40994 fieldset : function(c){
40995 var fs = new Roo.form.FieldSet(c);
40997 if(arguments.length > 1){ // duplicate code required because of Opera
40998 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41005 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41006 * fields are added and the container is closed. If no fields are passed the container remains open
41007 * until end() is called.
41008 * @param {Object} config The config to pass to the Layout
41009 * @param {Field} field1 (optional)
41010 * @param {Field} field2 (optional)
41011 * @param {Field} etc (optional)
41012 * @return Layout The container object
41014 container : function(c){
41015 var l = new Roo.form.Layout(c);
41017 if(arguments.length > 1){ // duplicate code required because of Opera
41018 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41025 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41026 * @param {Object} container A Roo.form.Layout or subclass of Layout
41027 * @return {Form} this
41029 start : function(c){
41030 // cascade label info
41031 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41032 this.active.stack.push(c);
41033 c.ownerCt = this.active;
41039 * Closes the current open container
41040 * @return {Form} this
41043 if(this.active == this.root){
41046 this.active = this.active.ownerCt;
41051 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41052 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41053 * as the label of the field.
41054 * @param {Field} field1
41055 * @param {Field} field2 (optional)
41056 * @param {Field} etc. (optional)
41057 * @return {Form} this
41060 this.active.stack.push.apply(this.active.stack, arguments);
41061 this.allItems.push.apply(this.allItems,arguments);
41063 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41064 if(a[i].isFormField){
41069 Roo.form.Form.superclass.add.apply(this, r);
41079 * Find any element that has been added to a form, using it's ID or name
41080 * This can include framesets, columns etc. along with regular fields..
41081 * @param {String} id - id or name to find.
41083 * @return {Element} e - or false if nothing found.
41085 findbyId : function(id)
41091 Ext.each(this.allItems, function(f){
41092 if (f.id == id || f.name == id ){
41103 * Render this form into the passed container. This should only be called once!
41104 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41105 * @return {Form} this
41107 render : function(ct)
41113 var o = this.autoCreate || {
41115 method : this.method || 'POST',
41116 id : this.id || Roo.id()
41118 this.initEl(ct.createChild(o));
41120 this.root.render(this.el);
41124 this.items.each(function(f){
41125 f.render('x-form-el-'+f.id);
41128 if(this.buttons.length > 0){
41129 // tables are required to maintain order and for correct IE layout
41130 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41131 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41132 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41134 var tr = tb.getElementsByTagName('tr')[0];
41135 for(var i = 0, len = this.buttons.length; i < len; i++) {
41136 var b = this.buttons[i];
41137 var td = document.createElement('td');
41138 td.className = 'x-form-btn-td';
41139 b.render(tr.appendChild(td));
41142 if(this.monitorValid){ // initialize after render
41143 this.startMonitoring();
41145 this.fireEvent('rendered', this);
41150 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41151 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41152 * object or a valid Roo.DomHelper element config
41153 * @param {Function} handler The function called when the button is clicked
41154 * @param {Object} scope (optional) The scope of the handler function
41155 * @return {Roo.Button}
41157 addButton : function(config, handler, scope){
41161 minWidth: this.minButtonWidth,
41164 if(typeof config == "string"){
41167 Roo.apply(bc, config);
41169 var btn = new Roo.Button(null, bc);
41170 this.buttons.push(btn);
41175 * Adds a series of form elements (using the xtype property as the factory method.
41176 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41177 * @param {Object} config
41180 addxtype : function()
41182 var ar = Array.prototype.slice.call(arguments, 0);
41184 for(var i = 0; i < ar.length; i++) {
41186 continue; // skip -- if this happends something invalid got sent, we
41187 // should ignore it, as basically that interface element will not show up
41188 // and that should be pretty obvious!!
41191 if (Roo.form[ar[i].xtype]) {
41193 var fe = Roo.factory(ar[i], Roo.form);
41199 fe.store.form = this;
41204 this.allItems.push(fe);
41205 if (fe.items && fe.addxtype) {
41206 fe.addxtype.apply(fe, fe.items);
41216 // console.log('adding ' + ar[i].xtype);
41218 if (ar[i].xtype == 'Button') {
41219 //console.log('adding button');
41220 //console.log(ar[i]);
41221 this.addButton(ar[i]);
41222 this.allItems.push(fe);
41226 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41227 alert('end is not supported on xtype any more, use items');
41229 // //console.log('adding end');
41237 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41238 * option "monitorValid"
41240 startMonitoring : function(){
41243 Roo.TaskMgr.start({
41244 run : this.bindHandler,
41245 interval : this.monitorPoll || 200,
41252 * Stops monitoring of the valid state of this form
41254 stopMonitoring : function(){
41255 this.bound = false;
41259 bindHandler : function(){
41261 return false; // stops binding
41264 this.items.each(function(f){
41265 if(!f.isValid(true)){
41270 for(var i = 0, len = this.buttons.length; i < len; i++){
41271 var btn = this.buttons[i];
41272 if(btn.formBind === true && btn.disabled === valid){
41273 btn.setDisabled(!valid);
41276 this.fireEvent('clientvalidation', this, valid);
41290 Roo.Form = Roo.form.Form;
41293 * Ext JS Library 1.1.1
41294 * Copyright(c) 2006-2007, Ext JS, LLC.
41296 * Originally Released Under LGPL - original licence link has changed is not relivant.
41299 * <script type="text/javascript">
41303 * @class Roo.form.Action
41304 * Internal Class used to handle form actions
41306 * @param {Roo.form.BasicForm} el The form element or its id
41307 * @param {Object} config Configuration options
41311 // define the action interface
41312 Roo.form.Action = function(form, options){
41314 this.options = options || {};
41317 * Client Validation Failed
41320 Roo.form.Action.CLIENT_INVALID = 'client';
41322 * Server Validation Failed
41325 Roo.form.Action.SERVER_INVALID = 'server';
41327 * Connect to Server Failed
41330 Roo.form.Action.CONNECT_FAILURE = 'connect';
41332 * Reading Data from Server Failed
41335 Roo.form.Action.LOAD_FAILURE = 'load';
41337 Roo.form.Action.prototype = {
41339 failureType : undefined,
41340 response : undefined,
41341 result : undefined,
41343 // interface method
41344 run : function(options){
41348 // interface method
41349 success : function(response){
41353 // interface method
41354 handleResponse : function(response){
41358 // default connection failure
41359 failure : function(response){
41360 this.response = response;
41361 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41362 this.form.afterAction(this, false);
41365 processResponse : function(response){
41366 this.response = response;
41367 if(!response.responseText){
41370 this.result = this.handleResponse(response);
41371 return this.result;
41374 // utility functions used internally
41375 getUrl : function(appendParams){
41376 var url = this.options.url || this.form.url || this.form.el.dom.action;
41378 var p = this.getParams();
41380 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41386 getMethod : function(){
41387 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41390 getParams : function(){
41391 var bp = this.form.baseParams;
41392 var p = this.options.params;
41394 if(typeof p == "object"){
41395 p = Roo.urlEncode(Roo.applyIf(p, bp));
41396 }else if(typeof p == 'string' && bp){
41397 p += '&' + Roo.urlEncode(bp);
41400 p = Roo.urlEncode(bp);
41405 createCallback : function(){
41407 success: this.success,
41408 failure: this.failure,
41410 timeout: (this.form.timeout*1000),
41411 upload: this.form.fileUpload ? this.success : undefined
41416 Roo.form.Action.Submit = function(form, options){
41417 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41420 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41423 haveProgress : false,
41424 uploadComplete : false,
41426 // uploadProgress indicator.
41427 uploadProgress : function()
41429 if (!this.form.progressUrl) {
41433 if (!this.haveProgress) {
41434 Roo.MessageBox.progress("Uploading", "Uploading");
41436 if (this.uploadComplete) {
41437 Roo.MessageBox.hide();
41441 this.haveProgress = true;
41443 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41445 var c = new Roo.data.Connection();
41447 url : this.form.progressUrl,
41452 success : function(req){
41453 //console.log(data);
41457 rdata = Roo.decode(req.responseText)
41459 Roo.log("Invalid data from server..");
41463 if (!rdata || !rdata.success) {
41467 var data = rdata.data;
41469 if (this.uploadComplete) {
41470 Roo.MessageBox.hide();
41475 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41476 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41479 this.uploadProgress.defer(2000,this);
41482 failure: function(data) {
41483 Roo.log('progress url failed ');
41494 // run get Values on the form, so it syncs any secondary forms.
41495 this.form.getValues();
41497 var o = this.options;
41498 var method = this.getMethod();
41499 var isPost = method == 'POST';
41500 if(o.clientValidation === false || this.form.isValid()){
41502 if (this.form.progressUrl) {
41503 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41504 (new Date() * 1) + '' + Math.random());
41508 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41509 form:this.form.el.dom,
41510 url:this.getUrl(!isPost),
41512 params:isPost ? this.getParams() : null,
41513 isUpload: this.form.fileUpload
41516 this.uploadProgress();
41518 }else if (o.clientValidation !== false){ // client validation failed
41519 this.failureType = Roo.form.Action.CLIENT_INVALID;
41520 this.form.afterAction(this, false);
41524 success : function(response)
41526 this.uploadComplete= true;
41527 if (this.haveProgress) {
41528 Roo.MessageBox.hide();
41531 var result = this.processResponse(response);
41532 if(result === true || result.success){
41533 this.form.afterAction(this, true);
41537 this.form.markInvalid(result.errors);
41538 this.failureType = Roo.form.Action.SERVER_INVALID;
41540 this.form.afterAction(this, false);
41542 failure : function(response)
41544 this.uploadComplete= true;
41545 if (this.haveProgress) {
41546 Roo.MessageBox.hide();
41549 this.response = response;
41550 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41551 this.form.afterAction(this, false);
41554 handleResponse : function(response){
41555 if(this.form.errorReader){
41556 var rs = this.form.errorReader.read(response);
41559 for(var i = 0, len = rs.records.length; i < len; i++) {
41560 var r = rs.records[i];
41561 errors[i] = r.data;
41564 if(errors.length < 1){
41568 success : rs.success,
41574 ret = Roo.decode(response.responseText);
41578 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41588 Roo.form.Action.Load = function(form, options){
41589 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41590 this.reader = this.form.reader;
41593 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41597 Roo.Ajax.request(Roo.apply(
41598 this.createCallback(), {
41599 method:this.getMethod(),
41600 url:this.getUrl(false),
41601 params:this.getParams()
41605 success : function(response){
41606 var result = this.processResponse(response);
41607 if(result === true || !result.success || !result.data){
41608 this.failureType = Roo.form.Action.LOAD_FAILURE;
41609 this.form.afterAction(this, false);
41612 this.form.clearInvalid();
41613 this.form.setValues(result.data);
41614 this.form.afterAction(this, true);
41617 handleResponse : function(response){
41618 if(this.form.reader){
41619 var rs = this.form.reader.read(response);
41620 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41622 success : rs.success,
41626 return Roo.decode(response.responseText);
41630 Roo.form.Action.ACTION_TYPES = {
41631 'load' : Roo.form.Action.Load,
41632 'submit' : Roo.form.Action.Submit
41635 * Ext JS Library 1.1.1
41636 * Copyright(c) 2006-2007, Ext JS, LLC.
41638 * Originally Released Under LGPL - original licence link has changed is not relivant.
41641 * <script type="text/javascript">
41645 * @class Roo.form.Layout
41646 * @extends Roo.Component
41647 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41649 * @param {Object} config Configuration options
41651 Roo.form.Layout = function(config){
41653 if (config.items) {
41654 xitems = config.items;
41655 delete config.items;
41657 Roo.form.Layout.superclass.constructor.call(this, config);
41659 Roo.each(xitems, this.addxtype, this);
41663 Roo.extend(Roo.form.Layout, Roo.Component, {
41665 * @cfg {String/Object} autoCreate
41666 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41669 * @cfg {String/Object/Function} style
41670 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41671 * a function which returns such a specification.
41674 * @cfg {String} labelAlign
41675 * Valid values are "left," "top" and "right" (defaults to "left")
41678 * @cfg {Number} labelWidth
41679 * Fixed width in pixels of all field labels (defaults to undefined)
41682 * @cfg {Boolean} clear
41683 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41687 * @cfg {String} labelSeparator
41688 * The separator to use after field labels (defaults to ':')
41690 labelSeparator : ':',
41692 * @cfg {Boolean} hideLabels
41693 * True to suppress the display of field labels in this layout (defaults to false)
41695 hideLabels : false,
41698 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41703 onRender : function(ct, position){
41704 if(this.el){ // from markup
41705 this.el = Roo.get(this.el);
41706 }else { // generate
41707 var cfg = this.getAutoCreate();
41708 this.el = ct.createChild(cfg, position);
41711 this.el.applyStyles(this.style);
41713 if(this.labelAlign){
41714 this.el.addClass('x-form-label-'+this.labelAlign);
41716 if(this.hideLabels){
41717 this.labelStyle = "display:none";
41718 this.elementStyle = "padding-left:0;";
41720 if(typeof this.labelWidth == 'number'){
41721 this.labelStyle = "width:"+this.labelWidth+"px;";
41722 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41724 if(this.labelAlign == 'top'){
41725 this.labelStyle = "width:auto;";
41726 this.elementStyle = "padding-left:0;";
41729 var stack = this.stack;
41730 var slen = stack.length;
41732 if(!this.fieldTpl){
41733 var t = new Roo.Template(
41734 '<div class="x-form-item {5}">',
41735 '<label for="{0}" style="{2}">{1}{4}</label>',
41736 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41738 '</div><div class="x-form-clear-left"></div>'
41740 t.disableFormats = true;
41742 Roo.form.Layout.prototype.fieldTpl = t;
41744 for(var i = 0; i < slen; i++) {
41745 if(stack[i].isFormField){
41746 this.renderField(stack[i]);
41748 this.renderComponent(stack[i]);
41753 this.el.createChild({cls:'x-form-clear'});
41758 renderField : function(f){
41759 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41762 f.labelStyle||this.labelStyle||'', //2
41763 this.elementStyle||'', //3
41764 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41765 f.itemCls||this.itemCls||'' //5
41766 ], true).getPrevSibling());
41770 renderComponent : function(c){
41771 c.render(c.isLayout ? this.el : this.el.createChild());
41774 * Adds a object form elements (using the xtype property as the factory method.)
41775 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41776 * @param {Object} config
41778 addxtype : function(o)
41780 // create the lement.
41781 o.form = this.form;
41782 var fe = Roo.factory(o, Roo.form);
41783 this.form.allItems.push(fe);
41784 this.stack.push(fe);
41786 if (fe.isFormField) {
41787 this.form.items.add(fe);
41795 * @class Roo.form.Column
41796 * @extends Roo.form.Layout
41797 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41799 * @param {Object} config Configuration options
41801 Roo.form.Column = function(config){
41802 Roo.form.Column.superclass.constructor.call(this, config);
41805 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41807 * @cfg {Number/String} width
41808 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41811 * @cfg {String/Object} autoCreate
41812 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41816 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41819 onRender : function(ct, position){
41820 Roo.form.Column.superclass.onRender.call(this, ct, position);
41822 this.el.setWidth(this.width);
41829 * @class Roo.form.Row
41830 * @extends Roo.form.Layout
41831 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41833 * @param {Object} config Configuration options
41837 Roo.form.Row = function(config){
41838 Roo.form.Row.superclass.constructor.call(this, config);
41841 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41843 * @cfg {Number/String} width
41844 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41847 * @cfg {Number/String} height
41848 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41850 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41854 onRender : function(ct, position){
41855 //console.log('row render');
41857 var t = new Roo.Template(
41858 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41859 '<label for="{0}" style="{2}">{1}{4}</label>',
41860 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41864 t.disableFormats = true;
41866 Roo.form.Layout.prototype.rowTpl = t;
41868 this.fieldTpl = this.rowTpl;
41870 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41871 var labelWidth = 100;
41873 if ((this.labelAlign != 'top')) {
41874 if (typeof this.labelWidth == 'number') {
41875 labelWidth = this.labelWidth
41877 this.padWidth = 20 + labelWidth;
41881 Roo.form.Column.superclass.onRender.call(this, ct, position);
41883 this.el.setWidth(this.width);
41886 this.el.setHeight(this.height);
41891 renderField : function(f){
41892 f.fieldEl = this.fieldTpl.append(this.el, [
41893 f.id, f.fieldLabel,
41894 f.labelStyle||this.labelStyle||'',
41895 this.elementStyle||'',
41896 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41897 f.itemCls||this.itemCls||'',
41898 f.width ? f.width + this.padWidth : 160 + this.padWidth
41905 * @class Roo.form.FieldSet
41906 * @extends Roo.form.Layout
41907 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41909 * @param {Object} config Configuration options
41911 Roo.form.FieldSet = function(config){
41912 Roo.form.FieldSet.superclass.constructor.call(this, config);
41915 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41917 * @cfg {String} legend
41918 * The text to display as the legend for the FieldSet (defaults to '')
41921 * @cfg {String/Object} autoCreate
41922 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41926 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41929 onRender : function(ct, position){
41930 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
41932 this.setLegend(this.legend);
41937 setLegend : function(text){
41939 this.el.child('legend').update(text);
41944 * Ext JS Library 1.1.1
41945 * Copyright(c) 2006-2007, Ext JS, LLC.
41947 * Originally Released Under LGPL - original licence link has changed is not relivant.
41950 * <script type="text/javascript">
41953 * @class Roo.form.VTypes
41954 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41957 Roo.form.VTypes = function(){
41958 // closure these in so they are only created once.
41959 var alpha = /^[a-zA-Z_]+$/;
41960 var alphanum = /^[a-zA-Z0-9_]+$/;
41961 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41962 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41964 // All these messages and functions are configurable
41967 * The function used to validate email addresses
41968 * @param {String} value The email address
41970 'email' : function(v){
41971 return email.test(v);
41974 * The error text to display when the email validation function returns false
41977 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41979 * The keystroke filter mask to be applied on email input
41982 'emailMask' : /[a-z0-9_\.\-@]/i,
41985 * The function used to validate URLs
41986 * @param {String} value The URL
41988 'url' : function(v){
41989 return url.test(v);
41992 * The error text to display when the url validation function returns false
41995 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41998 * The function used to validate alpha values
41999 * @param {String} value The value
42001 'alpha' : function(v){
42002 return alpha.test(v);
42005 * The error text to display when the alpha validation function returns false
42008 'alphaText' : 'This field should only contain letters and _',
42010 * The keystroke filter mask to be applied on alpha input
42013 'alphaMask' : /[a-z_]/i,
42016 * The function used to validate alphanumeric values
42017 * @param {String} value The value
42019 'alphanum' : function(v){
42020 return alphanum.test(v);
42023 * The error text to display when the alphanumeric validation function returns false
42026 'alphanumText' : 'This field should only contain letters, numbers and _',
42028 * The keystroke filter mask to be applied on alphanumeric input
42031 'alphanumMask' : /[a-z0-9_]/i
42033 }();//<script type="text/javascript">
42036 * @class Roo.form.FCKeditor
42037 * @extends Roo.form.TextArea
42038 * Wrapper around the FCKEditor http://www.fckeditor.net
42040 * Creates a new FCKeditor
42041 * @param {Object} config Configuration options
42043 Roo.form.FCKeditor = function(config){
42044 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42047 * @event editorinit
42048 * Fired when the editor is initialized - you can add extra handlers here..
42049 * @param {FCKeditor} this
42050 * @param {Object} the FCK object.
42057 Roo.form.FCKeditor.editors = { };
42058 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42060 //defaultAutoCreate : {
42061 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42065 * @cfg {Object} fck options - see fck manual for details.
42070 * @cfg {Object} fck toolbar set (Basic or Default)
42072 toolbarSet : 'Basic',
42074 * @cfg {Object} fck BasePath
42076 basePath : '/fckeditor/',
42084 onRender : function(ct, position)
42087 this.defaultAutoCreate = {
42089 style:"width:300px;height:60px;",
42090 autocomplete: "off"
42093 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42096 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42097 if(this.preventScrollbars){
42098 this.el.setStyle("overflow", "hidden");
42100 this.el.setHeight(this.growMin);
42103 //console.log('onrender' + this.getId() );
42104 Roo.form.FCKeditor.editors[this.getId()] = this;
42107 this.replaceTextarea() ;
42111 getEditor : function() {
42112 return this.fckEditor;
42115 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42116 * @param {Mixed} value The value to set
42120 setValue : function(value)
42122 //console.log('setValue: ' + value);
42124 if(typeof(value) == 'undefined') { // not sure why this is happending...
42127 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42129 //if(!this.el || !this.getEditor()) {
42130 // this.value = value;
42131 //this.setValue.defer(100,this,[value]);
42135 if(!this.getEditor()) {
42139 this.getEditor().SetData(value);
42146 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42147 * @return {Mixed} value The field value
42149 getValue : function()
42152 if (this.frame && this.frame.dom.style.display == 'none') {
42153 return Roo.form.FCKeditor.superclass.getValue.call(this);
42156 if(!this.el || !this.getEditor()) {
42158 // this.getValue.defer(100,this);
42163 var value=this.getEditor().GetData();
42164 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42165 return Roo.form.FCKeditor.superclass.getValue.call(this);
42171 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42172 * @return {Mixed} value The field value
42174 getRawValue : function()
42176 if (this.frame && this.frame.dom.style.display == 'none') {
42177 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42180 if(!this.el || !this.getEditor()) {
42181 //this.getRawValue.defer(100,this);
42188 var value=this.getEditor().GetData();
42189 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42190 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42194 setSize : function(w,h) {
42198 //if (this.frame && this.frame.dom.style.display == 'none') {
42199 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42202 //if(!this.el || !this.getEditor()) {
42203 // this.setSize.defer(100,this, [w,h]);
42209 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42211 this.frame.dom.setAttribute('width', w);
42212 this.frame.dom.setAttribute('height', h);
42213 this.frame.setSize(w,h);
42217 toggleSourceEdit : function(value) {
42221 this.el.dom.style.display = value ? '' : 'none';
42222 this.frame.dom.style.display = value ? 'none' : '';
42227 focus: function(tag)
42229 if (this.frame.dom.style.display == 'none') {
42230 return Roo.form.FCKeditor.superclass.focus.call(this);
42232 if(!this.el || !this.getEditor()) {
42233 this.focus.defer(100,this, [tag]);
42240 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42241 this.getEditor().Focus();
42243 if (!this.getEditor().Selection.GetSelection()) {
42244 this.focus.defer(100,this, [tag]);
42249 var r = this.getEditor().EditorDocument.createRange();
42250 r.setStart(tgs[0],0);
42251 r.setEnd(tgs[0],0);
42252 this.getEditor().Selection.GetSelection().removeAllRanges();
42253 this.getEditor().Selection.GetSelection().addRange(r);
42254 this.getEditor().Focus();
42261 replaceTextarea : function()
42263 if ( document.getElementById( this.getId() + '___Frame' ) )
42265 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42267 // We must check the elements firstly using the Id and then the name.
42268 var oTextarea = document.getElementById( this.getId() );
42270 var colElementsByName = document.getElementsByName( this.getId() ) ;
42272 oTextarea.style.display = 'none' ;
42274 if ( oTextarea.tabIndex ) {
42275 this.TabIndex = oTextarea.tabIndex ;
42278 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42279 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42280 this.frame = Roo.get(this.getId() + '___Frame')
42283 _getConfigHtml : function()
42287 for ( var o in this.fckconfig ) {
42288 sConfig += sConfig.length > 0 ? '&' : '';
42289 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42292 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42296 _getIFrameHtml : function()
42298 var sFile = 'fckeditor.html' ;
42299 /* no idea what this is about..
42302 if ( (/fcksource=true/i).test( window.top.location.search ) )
42303 sFile = 'fckeditor.original.html' ;
42308 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42309 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42312 var html = '<iframe id="' + this.getId() +
42313 '___Frame" src="' + sLink +
42314 '" width="' + this.width +
42315 '" height="' + this.height + '"' +
42316 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42317 ' frameborder="0" scrolling="no"></iframe>' ;
42322 _insertHtmlBefore : function( html, element )
42324 if ( element.insertAdjacentHTML ) {
42326 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42328 var oRange = document.createRange() ;
42329 oRange.setStartBefore( element ) ;
42330 var oFragment = oRange.createContextualFragment( html );
42331 element.parentNode.insertBefore( oFragment, element ) ;
42344 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42346 function FCKeditor_OnComplete(editorInstance){
42347 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42348 f.fckEditor = editorInstance;
42349 //console.log("loaded");
42350 f.fireEvent('editorinit', f, editorInstance);
42370 //<script type="text/javascript">
42372 * @class Roo.form.GridField
42373 * @extends Roo.form.Field
42374 * Embed a grid (or editable grid into a form)
42377 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42379 * xgrid.store = Roo.data.Store
42380 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42381 * xgrid.store.reader = Roo.data.JsonReader
42385 * Creates a new GridField
42386 * @param {Object} config Configuration options
42388 Roo.form.GridField = function(config){
42389 Roo.form.GridField.superclass.constructor.call(this, config);
42393 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42395 * @cfg {Number} width - used to restrict width of grid..
42399 * @cfg {Number} height - used to restrict height of grid..
42403 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42409 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42410 * {tag: "input", type: "checkbox", autocomplete: "off"})
42412 // defaultAutoCreate : { tag: 'div' },
42413 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42415 * @cfg {String} addTitle Text to include for adding a title.
42419 onResize : function(){
42420 Roo.form.Field.superclass.onResize.apply(this, arguments);
42423 initEvents : function(){
42424 // Roo.form.Checkbox.superclass.initEvents.call(this);
42425 // has no events...
42430 getResizeEl : function(){
42434 getPositionEl : function(){
42439 onRender : function(ct, position){
42441 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42442 var style = this.style;
42445 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42446 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42447 this.viewEl = this.wrap.createChild({ tag: 'div' });
42449 this.viewEl.applyStyles(style);
42452 this.viewEl.setWidth(this.width);
42455 this.viewEl.setHeight(this.height);
42457 //if(this.inputValue !== undefined){
42458 //this.setValue(this.value);
42461 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42464 this.grid.render();
42465 this.grid.getDataSource().on('remove', this.refreshValue, this);
42466 this.grid.getDataSource().on('update', this.refreshValue, this);
42467 this.grid.on('afteredit', this.refreshValue, this);
42473 * Sets the value of the item.
42474 * @param {String} either an object or a string..
42476 setValue : function(v){
42478 v = v || []; // empty set..
42479 // this does not seem smart - it really only affects memoryproxy grids..
42480 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42481 var ds = this.grid.getDataSource();
42482 // assumes a json reader..
42484 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42485 ds.loadData( data);
42487 Roo.form.GridField.superclass.setValue.call(this, v);
42488 this.refreshValue();
42489 // should load data in the grid really....
42493 refreshValue: function() {
42495 this.grid.getDataSource().each(function(r) {
42498 this.el.dom.value = Roo.encode(val);
42506 * Ext JS Library 1.1.1
42507 * Copyright(c) 2006-2007, Ext JS, LLC.
42509 * Originally Released Under LGPL - original licence link has changed is not relivant.
42512 * <script type="text/javascript">
42515 * @class Roo.form.DisplayField
42516 * @extends Roo.form.Field
42517 * A generic Field to display non-editable data.
42519 * Creates a new Display Field item.
42520 * @param {Object} config Configuration options
42522 Roo.form.DisplayField = function(config){
42523 Roo.form.DisplayField.superclass.constructor.call(this, config);
42527 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42528 inputType: 'hidden',
42534 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42536 focusClass : undefined,
42538 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42540 fieldClass: 'x-form-field',
42543 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42545 valueRenderer: undefined,
42549 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42550 * {tag: "input", type: "checkbox", autocomplete: "off"})
42553 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42555 onResize : function(){
42556 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42560 initEvents : function(){
42561 // Roo.form.Checkbox.superclass.initEvents.call(this);
42562 // has no events...
42567 getResizeEl : function(){
42571 getPositionEl : function(){
42576 onRender : function(ct, position){
42578 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42579 //if(this.inputValue !== undefined){
42580 this.wrap = this.el.wrap();
42582 this.viewEl = this.wrap.createChild({ tag: 'div'});
42584 if (this.bodyStyle) {
42585 this.viewEl.applyStyles(this.bodyStyle);
42587 //this.viewEl.setStyle('padding', '2px');
42589 this.setValue(this.value);
42594 initValue : Roo.emptyFn,
42599 onClick : function(){
42604 * Sets the checked state of the checkbox.
42605 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42607 setValue : function(v){
42609 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42610 // this might be called before we have a dom element..
42611 if (!this.viewEl) {
42614 this.viewEl.dom.innerHTML = html;
42615 Roo.form.DisplayField.superclass.setValue.call(this, v);
42618 });//<script type="text/javasscript">
42622 * @class Roo.DDView
42623 * A DnD enabled version of Roo.View.
42624 * @param {Element/String} container The Element in which to create the View.
42625 * @param {String} tpl The template string used to create the markup for each element of the View
42626 * @param {Object} config The configuration properties. These include all the config options of
42627 * {@link Roo.View} plus some specific to this class.<br>
42629 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42630 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42632 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42633 .x-view-drag-insert-above {
42634 border-top:1px dotted #3366cc;
42636 .x-view-drag-insert-below {
42637 border-bottom:1px dotted #3366cc;
42643 Roo.DDView = function(container, tpl, config) {
42644 Roo.DDView.superclass.constructor.apply(this, arguments);
42645 this.getEl().setStyle("outline", "0px none");
42646 this.getEl().unselectable();
42647 if (this.dragGroup) {
42648 this.setDraggable(this.dragGroup.split(","));
42650 if (this.dropGroup) {
42651 this.setDroppable(this.dropGroup.split(","));
42653 if (this.deletable) {
42654 this.setDeletable();
42656 this.isDirtyFlag = false;
42662 Roo.extend(Roo.DDView, Roo.View, {
42663 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42664 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42665 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42666 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42670 reset: Roo.emptyFn,
42672 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42674 validate: function() {
42678 destroy: function() {
42679 this.purgeListeners();
42680 this.getEl.removeAllListeners();
42681 this.getEl().remove();
42682 if (this.dragZone) {
42683 if (this.dragZone.destroy) {
42684 this.dragZone.destroy();
42687 if (this.dropZone) {
42688 if (this.dropZone.destroy) {
42689 this.dropZone.destroy();
42694 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
42695 getName: function() {
42699 /** Loads the View from a JSON string representing the Records to put into the Store. */
42700 setValue: function(v) {
42702 throw "DDView.setValue(). DDView must be constructed with a valid Store";
42705 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
42706 this.store.proxy = new Roo.data.MemoryProxy(data);
42710 /** @return {String} a parenthesised list of the ids of the Records in the View. */
42711 getValue: function() {
42713 this.store.each(function(rec) {
42714 result += rec.id + ',';
42716 return result.substr(0, result.length - 1) + ')';
42719 getIds: function() {
42720 var i = 0, result = new Array(this.store.getCount());
42721 this.store.each(function(rec) {
42722 result[i++] = rec.id;
42727 isDirty: function() {
42728 return this.isDirtyFlag;
42732 * Part of the Roo.dd.DropZone interface. If no target node is found, the
42733 * whole Element becomes the target, and this causes the drop gesture to append.
42735 getTargetFromEvent : function(e) {
42736 var target = e.getTarget();
42737 while ((target !== null) && (target.parentNode != this.el.dom)) {
42738 target = target.parentNode;
42741 target = this.el.dom.lastChild || this.el.dom;
42747 * Create the drag data which consists of an object which has the property "ddel" as
42748 * the drag proxy element.
42750 getDragData : function(e) {
42751 var target = this.findItemFromChild(e.getTarget());
42753 this.handleSelection(e);
42754 var selNodes = this.getSelectedNodes();
42757 copy: this.copy || (this.allowCopy && e.ctrlKey),
42761 var selectedIndices = this.getSelectedIndexes();
42762 for (var i = 0; i < selectedIndices.length; i++) {
42763 dragData.records.push(this.store.getAt(selectedIndices[i]));
42765 if (selNodes.length == 1) {
42766 dragData.ddel = target.cloneNode(true); // the div element
42768 var div = document.createElement('div'); // create the multi element drag "ghost"
42769 div.className = 'multi-proxy';
42770 for (var i = 0, len = selNodes.length; i < len; i++) {
42771 div.appendChild(selNodes[i].cloneNode(true));
42773 dragData.ddel = div;
42775 //console.log(dragData)
42776 //console.log(dragData.ddel.innerHTML)
42779 //console.log('nodragData')
42783 /** Specify to which ddGroup items in this DDView may be dragged. */
42784 setDraggable: function(ddGroup) {
42785 if (ddGroup instanceof Array) {
42786 Roo.each(ddGroup, this.setDraggable, this);
42789 if (this.dragZone) {
42790 this.dragZone.addToGroup(ddGroup);
42792 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
42793 containerScroll: true,
42797 // Draggability implies selection. DragZone's mousedown selects the element.
42798 if (!this.multiSelect) { this.singleSelect = true; }
42800 // Wire the DragZone's handlers up to methods in *this*
42801 this.dragZone.getDragData = this.getDragData.createDelegate(this);
42805 /** Specify from which ddGroup this DDView accepts drops. */
42806 setDroppable: function(ddGroup) {
42807 if (ddGroup instanceof Array) {
42808 Roo.each(ddGroup, this.setDroppable, this);
42811 if (this.dropZone) {
42812 this.dropZone.addToGroup(ddGroup);
42814 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
42815 containerScroll: true,
42819 // Wire the DropZone's handlers up to methods in *this*
42820 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
42821 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
42822 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
42823 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
42824 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
42828 /** Decide whether to drop above or below a View node. */
42829 getDropPoint : function(e, n, dd){
42830 if (n == this.el.dom) { return "above"; }
42831 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
42832 var c = t + (b - t) / 2;
42833 var y = Roo.lib.Event.getPageY(e);
42841 onNodeEnter : function(n, dd, e, data){
42845 onNodeOver : function(n, dd, e, data){
42846 var pt = this.getDropPoint(e, n, dd);
42847 // set the insert point style on the target node
42848 var dragElClass = this.dropNotAllowed;
42851 if (pt == "above"){
42852 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
42853 targetElClass = "x-view-drag-insert-above";
42855 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
42856 targetElClass = "x-view-drag-insert-below";
42858 if (this.lastInsertClass != targetElClass){
42859 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
42860 this.lastInsertClass = targetElClass;
42863 return dragElClass;
42866 onNodeOut : function(n, dd, e, data){
42867 this.removeDropIndicators(n);
42870 onNodeDrop : function(n, dd, e, data){
42871 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
42874 var pt = this.getDropPoint(e, n, dd);
42875 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
42876 if (pt == "below") { insertAt++; }
42877 for (var i = 0; i < data.records.length; i++) {
42878 var r = data.records[i];
42879 var dup = this.store.getById(r.id);
42880 if (dup && (dd != this.dragZone)) {
42881 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
42884 this.store.insert(insertAt++, r.copy());
42886 data.source.isDirtyFlag = true;
42888 this.store.insert(insertAt++, r);
42890 this.isDirtyFlag = true;
42893 this.dragZone.cachedTarget = null;
42897 removeDropIndicators : function(n){
42899 Roo.fly(n).removeClass([
42900 "x-view-drag-insert-above",
42901 "x-view-drag-insert-below"]);
42902 this.lastInsertClass = "_noclass";
42907 * Utility method. Add a delete option to the DDView's context menu.
42908 * @param {String} imageUrl The URL of the "delete" icon image.
42910 setDeletable: function(imageUrl) {
42911 if (!this.singleSelect && !this.multiSelect) {
42912 this.singleSelect = true;
42914 var c = this.getContextMenu();
42915 this.contextMenu.on("itemclick", function(item) {
42918 this.remove(this.getSelectedIndexes());
42922 this.contextMenu.add({
42929 /** Return the context menu for this DDView. */
42930 getContextMenu: function() {
42931 if (!this.contextMenu) {
42932 // Create the View's context menu
42933 this.contextMenu = new Roo.menu.Menu({
42934 id: this.id + "-contextmenu"
42936 this.el.on("contextmenu", this.showContextMenu, this);
42938 return this.contextMenu;
42941 disableContextMenu: function() {
42942 if (this.contextMenu) {
42943 this.el.un("contextmenu", this.showContextMenu, this);
42947 showContextMenu: function(e, item) {
42948 item = this.findItemFromChild(e.getTarget());
42951 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
42952 this.contextMenu.showAt(e.getXY());
42957 * Remove {@link Roo.data.Record}s at the specified indices.
42958 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42960 remove: function(selectedIndices) {
42961 selectedIndices = [].concat(selectedIndices);
42962 for (var i = 0; i < selectedIndices.length; i++) {
42963 var rec = this.store.getAt(selectedIndices[i]);
42964 this.store.remove(rec);
42969 * Double click fires the event, but also, if this is draggable, and there is only one other
42970 * related DropZone, it transfers the selected node.
42972 onDblClick : function(e){
42973 var item = this.findItemFromChild(e.getTarget());
42975 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
42978 if (this.dragGroup) {
42979 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
42980 while (targets.indexOf(this.dropZone) > -1) {
42981 targets.remove(this.dropZone);
42983 if (targets.length == 1) {
42984 this.dragZone.cachedTarget = null;
42985 var el = Roo.get(targets[0].getEl());
42986 var box = el.getBox(true);
42987 targets[0].onNodeDrop(el.dom, {
42989 xy: [box.x, box.y + box.height - 1]
42990 }, null, this.getDragData(e));
42996 handleSelection: function(e) {
42997 this.dragZone.cachedTarget = null;
42998 var item = this.findItemFromChild(e.getTarget());
43000 this.clearSelections(true);
43003 if (item && (this.multiSelect || this.singleSelect)){
43004 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
43005 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
43006 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
43007 this.unselect(item);
43009 this.select(item, this.multiSelect && e.ctrlKey);
43010 this.lastSelection = item;
43015 onItemClick : function(item, index, e){
43016 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43022 unselect : function(nodeInfo, suppressEvent){
43023 var node = this.getNode(nodeInfo);
43024 if(node && this.isSelected(node)){
43025 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43026 Roo.fly(node).removeClass(this.selectedClass);
43027 this.selections.remove(node);
43028 if(!suppressEvent){
43029 this.fireEvent("selectionchange", this, this.selections);
43037 * Ext JS Library 1.1.1
43038 * Copyright(c) 2006-2007, Ext JS, LLC.
43040 * Originally Released Under LGPL - original licence link has changed is not relivant.
43043 * <script type="text/javascript">
43047 * @class Roo.LayoutManager
43048 * @extends Roo.util.Observable
43049 * Base class for layout managers.
43051 Roo.LayoutManager = function(container, config){
43052 Roo.LayoutManager.superclass.constructor.call(this);
43053 this.el = Roo.get(container);
43054 // ie scrollbar fix
43055 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43056 document.body.scroll = "no";
43057 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43058 this.el.position('relative');
43060 this.id = this.el.id;
43061 this.el.addClass("x-layout-container");
43062 /** false to disable window resize monitoring @type Boolean */
43063 this.monitorWindowResize = true;
43068 * Fires when a layout is performed.
43069 * @param {Roo.LayoutManager} this
43073 * @event regionresized
43074 * Fires when the user resizes a region.
43075 * @param {Roo.LayoutRegion} region The resized region
43076 * @param {Number} newSize The new size (width for east/west, height for north/south)
43078 "regionresized" : true,
43080 * @event regioncollapsed
43081 * Fires when a region is collapsed.
43082 * @param {Roo.LayoutRegion} region The collapsed region
43084 "regioncollapsed" : true,
43086 * @event regionexpanded
43087 * Fires when a region is expanded.
43088 * @param {Roo.LayoutRegion} region The expanded region
43090 "regionexpanded" : true
43092 this.updating = false;
43093 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43096 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43098 * Returns true if this layout is currently being updated
43099 * @return {Boolean}
43101 isUpdating : function(){
43102 return this.updating;
43106 * Suspend the LayoutManager from doing auto-layouts while
43107 * making multiple add or remove calls
43109 beginUpdate : function(){
43110 this.updating = true;
43114 * Restore auto-layouts and optionally disable the manager from performing a layout
43115 * @param {Boolean} noLayout true to disable a layout update
43117 endUpdate : function(noLayout){
43118 this.updating = false;
43124 layout: function(){
43128 onRegionResized : function(region, newSize){
43129 this.fireEvent("regionresized", region, newSize);
43133 onRegionCollapsed : function(region){
43134 this.fireEvent("regioncollapsed", region);
43137 onRegionExpanded : function(region){
43138 this.fireEvent("regionexpanded", region);
43142 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43143 * performs box-model adjustments.
43144 * @return {Object} The size as an object {width: (the width), height: (the height)}
43146 getViewSize : function(){
43148 if(this.el.dom != document.body){
43149 size = this.el.getSize();
43151 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43153 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43154 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43159 * Returns the Element this layout is bound to.
43160 * @return {Roo.Element}
43162 getEl : function(){
43167 * Returns the specified region.
43168 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43169 * @return {Roo.LayoutRegion}
43171 getRegion : function(target){
43172 return this.regions[target.toLowerCase()];
43175 onWindowResize : function(){
43176 if(this.monitorWindowResize){
43182 * Ext JS Library 1.1.1
43183 * Copyright(c) 2006-2007, Ext JS, LLC.
43185 * Originally Released Under LGPL - original licence link has changed is not relivant.
43188 * <script type="text/javascript">
43191 * @class Roo.BorderLayout
43192 * @extends Roo.LayoutManager
43193 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43194 * please see: <br><br>
43195 * <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>
43196 * <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>
43199 var layout = new Roo.BorderLayout(document.body, {
43233 preferredTabWidth: 150
43238 var CP = Roo.ContentPanel;
43240 layout.beginUpdate();
43241 layout.add("north", new CP("north", "North"));
43242 layout.add("south", new CP("south", {title: "South", closable: true}));
43243 layout.add("west", new CP("west", {title: "West"}));
43244 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43245 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43246 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43247 layout.getRegion("center").showPanel("center1");
43248 layout.endUpdate();
43251 <b>The container the layout is rendered into can be either the body element or any other element.
43252 If it is not the body element, the container needs to either be an absolute positioned element,
43253 or you will need to add "position:relative" to the css of the container. You will also need to specify
43254 the container size if it is not the body element.</b>
43257 * Create a new BorderLayout
43258 * @param {String/HTMLElement/Element} container The container this layout is bound to
43259 * @param {Object} config Configuration options
43261 Roo.BorderLayout = function(container, config){
43262 config = config || {};
43263 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43264 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43265 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43266 var target = this.factory.validRegions[i];
43267 if(config[target]){
43268 this.addRegion(target, config[target]);
43273 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43275 * Creates and adds a new region if it doesn't already exist.
43276 * @param {String} target The target region key (north, south, east, west or center).
43277 * @param {Object} config The regions config object
43278 * @return {BorderLayoutRegion} The new region
43280 addRegion : function(target, config){
43281 if(!this.regions[target]){
43282 var r = this.factory.create(target, this, config);
43283 this.bindRegion(target, r);
43285 return this.regions[target];
43289 bindRegion : function(name, r){
43290 this.regions[name] = r;
43291 r.on("visibilitychange", this.layout, this);
43292 r.on("paneladded", this.layout, this);
43293 r.on("panelremoved", this.layout, this);
43294 r.on("invalidated", this.layout, this);
43295 r.on("resized", this.onRegionResized, this);
43296 r.on("collapsed", this.onRegionCollapsed, this);
43297 r.on("expanded", this.onRegionExpanded, this);
43301 * Performs a layout update.
43303 layout : function(){
43304 if(this.updating) return;
43305 var size = this.getViewSize();
43306 var w = size.width;
43307 var h = size.height;
43312 //var x = 0, y = 0;
43314 var rs = this.regions;
43315 var north = rs["north"];
43316 var south = rs["south"];
43317 var west = rs["west"];
43318 var east = rs["east"];
43319 var center = rs["center"];
43320 //if(this.hideOnLayout){ // not supported anymore
43321 //c.el.setStyle("display", "none");
43323 if(north && north.isVisible()){
43324 var b = north.getBox();
43325 var m = north.getMargins();
43326 b.width = w - (m.left+m.right);
43329 centerY = b.height + b.y + m.bottom;
43330 centerH -= centerY;
43331 north.updateBox(this.safeBox(b));
43333 if(south && south.isVisible()){
43334 var b = south.getBox();
43335 var m = south.getMargins();
43336 b.width = w - (m.left+m.right);
43338 var totalHeight = (b.height + m.top + m.bottom);
43339 b.y = h - totalHeight + m.top;
43340 centerH -= totalHeight;
43341 south.updateBox(this.safeBox(b));
43343 if(west && west.isVisible()){
43344 var b = west.getBox();
43345 var m = west.getMargins();
43346 b.height = centerH - (m.top+m.bottom);
43348 b.y = centerY + m.top;
43349 var totalWidth = (b.width + m.left + m.right);
43350 centerX += totalWidth;
43351 centerW -= totalWidth;
43352 west.updateBox(this.safeBox(b));
43354 if(east && east.isVisible()){
43355 var b = east.getBox();
43356 var m = east.getMargins();
43357 b.height = centerH - (m.top+m.bottom);
43358 var totalWidth = (b.width + m.left + m.right);
43359 b.x = w - totalWidth + m.left;
43360 b.y = centerY + m.top;
43361 centerW -= totalWidth;
43362 east.updateBox(this.safeBox(b));
43365 var m = center.getMargins();
43367 x: centerX + m.left,
43368 y: centerY + m.top,
43369 width: centerW - (m.left+m.right),
43370 height: centerH - (m.top+m.bottom)
43372 //if(this.hideOnLayout){
43373 //center.el.setStyle("display", "block");
43375 center.updateBox(this.safeBox(centerBox));
43378 this.fireEvent("layout", this);
43382 safeBox : function(box){
43383 box.width = Math.max(0, box.width);
43384 box.height = Math.max(0, box.height);
43389 * Adds a ContentPanel (or subclass) to this layout.
43390 * @param {String} target The target region key (north, south, east, west or center).
43391 * @param {Roo.ContentPanel} panel The panel to add
43392 * @return {Roo.ContentPanel} The added panel
43394 add : function(target, panel){
43396 target = target.toLowerCase();
43397 return this.regions[target].add(panel);
43401 * Remove a ContentPanel (or subclass) to this layout.
43402 * @param {String} target The target region key (north, south, east, west or center).
43403 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43404 * @return {Roo.ContentPanel} The removed panel
43406 remove : function(target, panel){
43407 target = target.toLowerCase();
43408 return this.regions[target].remove(panel);
43412 * Searches all regions for a panel with the specified id
43413 * @param {String} panelId
43414 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43416 findPanel : function(panelId){
43417 var rs = this.regions;
43418 for(var target in rs){
43419 if(typeof rs[target] != "function"){
43420 var p = rs[target].getPanel(panelId);
43430 * Searches all regions for a panel with the specified id and activates (shows) it.
43431 * @param {String/ContentPanel} panelId The panels id or the panel itself
43432 * @return {Roo.ContentPanel} The shown panel or null
43434 showPanel : function(panelId) {
43435 var rs = this.regions;
43436 for(var target in rs){
43437 var r = rs[target];
43438 if(typeof r != "function"){
43439 if(r.hasPanel(panelId)){
43440 return r.showPanel(panelId);
43448 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43449 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43451 restoreState : function(provider){
43453 provider = Roo.state.Manager;
43455 var sm = new Roo.LayoutStateManager();
43456 sm.init(this, provider);
43460 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43461 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43462 * a valid ContentPanel config object. Example:
43464 // Create the main layout
43465 var layout = new Roo.BorderLayout('main-ct', {
43476 // Create and add multiple ContentPanels at once via configs
43479 id: 'source-files',
43481 title:'Ext Source Files',
43494 * @param {Object} regions An object containing ContentPanel configs by region name
43496 batchAdd : function(regions){
43497 this.beginUpdate();
43498 for(var rname in regions){
43499 var lr = this.regions[rname];
43501 this.addTypedPanels(lr, regions[rname]);
43508 addTypedPanels : function(lr, ps){
43509 if(typeof ps == 'string'){
43510 lr.add(new Roo.ContentPanel(ps));
43512 else if(ps instanceof Array){
43513 for(var i =0, len = ps.length; i < len; i++){
43514 this.addTypedPanels(lr, ps[i]);
43517 else if(!ps.events){ // raw config?
43519 delete ps.el; // prevent conflict
43520 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43522 else { // panel object assumed!
43527 * Adds a xtype elements to the layout.
43531 xtype : 'ContentPanel',
43538 xtype : 'NestedLayoutPanel',
43544 items : [ ... list of content panels or nested layout panels.. ]
43548 * @param {Object} cfg Xtype definition of item to add.
43550 addxtype : function(cfg)
43552 // basically accepts a pannel...
43553 // can accept a layout region..!?!?
43554 // console.log('BorderLayout add ' + cfg.xtype)
43556 if (!cfg.xtype.match(/Panel$/)) {
43560 var region = cfg.region;
43566 xitems = cfg.items;
43573 case 'ContentPanel': // ContentPanel (el, cfg)
43574 case 'ScrollPanel': // ContentPanel (el, cfg)
43575 if(cfg.autoCreate) {
43576 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43578 var el = this.el.createChild();
43579 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43582 this.add(region, ret);
43586 case 'TreePanel': // our new panel!
43587 cfg.el = this.el.createChild();
43588 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43589 this.add(region, ret);
43592 case 'NestedLayoutPanel':
43593 // create a new Layout (which is a Border Layout...
43594 var el = this.el.createChild();
43595 var clayout = cfg.layout;
43597 clayout.items = clayout.items || [];
43598 // replace this exitems with the clayout ones..
43599 xitems = clayout.items;
43602 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43603 cfg.background = false;
43605 var layout = new Roo.BorderLayout(el, clayout);
43607 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43608 //console.log('adding nested layout panel ' + cfg.toSource());
43609 this.add(region, ret);
43615 // needs grid and region
43617 //var el = this.getRegion(region).el.createChild();
43618 var el = this.el.createChild();
43619 // create the grid first...
43621 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43623 if (region == 'center' && this.active ) {
43624 cfg.background = false;
43626 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43628 this.add(region, ret);
43629 if (cfg.background) {
43630 ret.on('activate', function(gp) {
43631 if (!gp.grid.rendered) {
43644 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43646 // GridPanel (grid, cfg)
43649 this.beginUpdate();
43651 Roo.each(xitems, function(i) {
43661 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43662 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43663 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43664 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43667 var CP = Roo.ContentPanel;
43669 var layout = Roo.BorderLayout.create({
43673 panels: [new CP("north", "North")]
43682 panels: [new CP("west", {title: "West"})]
43691 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
43700 panels: [new CP("south", {title: "South", closable: true})]
43707 preferredTabWidth: 150,
43709 new CP("center1", {title: "Close Me", closable: true}),
43710 new CP("center2", {title: "Center Panel", closable: false})
43715 layout.getRegion("center").showPanel("center1");
43720 Roo.BorderLayout.create = function(config, targetEl){
43721 var layout = new Roo.BorderLayout(targetEl || document.body, config);
43722 layout.beginUpdate();
43723 var regions = Roo.BorderLayout.RegionFactory.validRegions;
43724 for(var j = 0, jlen = regions.length; j < jlen; j++){
43725 var lr = regions[j];
43726 if(layout.regions[lr] && config[lr].panels){
43727 var r = layout.regions[lr];
43728 var ps = config[lr].panels;
43729 layout.addTypedPanels(r, ps);
43732 layout.endUpdate();
43737 Roo.BorderLayout.RegionFactory = {
43739 validRegions : ["north","south","east","west","center"],
43742 create : function(target, mgr, config){
43743 target = target.toLowerCase();
43744 if(config.lightweight || config.basic){
43745 return new Roo.BasicLayoutRegion(mgr, config, target);
43749 return new Roo.NorthLayoutRegion(mgr, config);
43751 return new Roo.SouthLayoutRegion(mgr, config);
43753 return new Roo.EastLayoutRegion(mgr, config);
43755 return new Roo.WestLayoutRegion(mgr, config);
43757 return new Roo.CenterLayoutRegion(mgr, config);
43759 throw 'Layout region "'+target+'" not supported.';
43763 * Ext JS Library 1.1.1
43764 * Copyright(c) 2006-2007, Ext JS, LLC.
43766 * Originally Released Under LGPL - original licence link has changed is not relivant.
43769 * <script type="text/javascript">
43773 * @class Roo.BasicLayoutRegion
43774 * @extends Roo.util.Observable
43775 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
43776 * and does not have a titlebar, tabs or any other features. All it does is size and position
43777 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
43779 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
43781 this.position = pos;
43784 * @scope Roo.BasicLayoutRegion
43788 * @event beforeremove
43789 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
43790 * @param {Roo.LayoutRegion} this
43791 * @param {Roo.ContentPanel} panel The panel
43792 * @param {Object} e The cancel event object
43794 "beforeremove" : true,
43796 * @event invalidated
43797 * Fires when the layout for this region is changed.
43798 * @param {Roo.LayoutRegion} this
43800 "invalidated" : true,
43802 * @event visibilitychange
43803 * Fires when this region is shown or hidden
43804 * @param {Roo.LayoutRegion} this
43805 * @param {Boolean} visibility true or false
43807 "visibilitychange" : true,
43809 * @event paneladded
43810 * Fires when a panel is added.
43811 * @param {Roo.LayoutRegion} this
43812 * @param {Roo.ContentPanel} panel The panel
43814 "paneladded" : true,
43816 * @event panelremoved
43817 * Fires when a panel is removed.
43818 * @param {Roo.LayoutRegion} this
43819 * @param {Roo.ContentPanel} panel The panel
43821 "panelremoved" : true,
43824 * Fires when this region is collapsed.
43825 * @param {Roo.LayoutRegion} this
43827 "collapsed" : true,
43830 * Fires when this region is expanded.
43831 * @param {Roo.LayoutRegion} this
43836 * Fires when this region is slid into view.
43837 * @param {Roo.LayoutRegion} this
43839 "slideshow" : true,
43842 * Fires when this region slides out of view.
43843 * @param {Roo.LayoutRegion} this
43845 "slidehide" : true,
43847 * @event panelactivated
43848 * Fires when a panel is activated.
43849 * @param {Roo.LayoutRegion} this
43850 * @param {Roo.ContentPanel} panel The activated panel
43852 "panelactivated" : true,
43855 * Fires when the user resizes this region.
43856 * @param {Roo.LayoutRegion} this
43857 * @param {Number} newSize The new size (width for east/west, height for north/south)
43861 /** A collection of panels in this region. @type Roo.util.MixedCollection */
43862 this.panels = new Roo.util.MixedCollection();
43863 this.panels.getKey = this.getPanelId.createDelegate(this);
43865 this.activePanel = null;
43866 // ensure listeners are added...
43868 if (config.listeners || config.events) {
43869 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
43870 listeners : config.listeners || {},
43871 events : config.events || {}
43875 if(skipConfig !== true){
43876 this.applyConfig(config);
43880 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
43881 getPanelId : function(p){
43885 applyConfig : function(config){
43886 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43887 this.config = config;
43892 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
43893 * the width, for horizontal (north, south) the height.
43894 * @param {Number} newSize The new width or height
43896 resizeTo : function(newSize){
43897 var el = this.el ? this.el :
43898 (this.activePanel ? this.activePanel.getEl() : null);
43900 switch(this.position){
43903 el.setWidth(newSize);
43904 this.fireEvent("resized", this, newSize);
43908 el.setHeight(newSize);
43909 this.fireEvent("resized", this, newSize);
43915 getBox : function(){
43916 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
43919 getMargins : function(){
43920 return this.margins;
43923 updateBox : function(box){
43925 var el = this.activePanel.getEl();
43926 el.dom.style.left = box.x + "px";
43927 el.dom.style.top = box.y + "px";
43928 this.activePanel.setSize(box.width, box.height);
43932 * Returns the container element for this region.
43933 * @return {Roo.Element}
43935 getEl : function(){
43936 return this.activePanel;
43940 * Returns true if this region is currently visible.
43941 * @return {Boolean}
43943 isVisible : function(){
43944 return this.activePanel ? true : false;
43947 setActivePanel : function(panel){
43948 panel = this.getPanel(panel);
43949 if(this.activePanel && this.activePanel != panel){
43950 this.activePanel.setActiveState(false);
43951 this.activePanel.getEl().setLeftTop(-10000,-10000);
43953 this.activePanel = panel;
43954 panel.setActiveState(true);
43956 panel.setSize(this.box.width, this.box.height);
43958 this.fireEvent("panelactivated", this, panel);
43959 this.fireEvent("invalidated");
43963 * Show the specified panel.
43964 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43965 * @return {Roo.ContentPanel} The shown panel or null
43967 showPanel : function(panel){
43968 if(panel = this.getPanel(panel)){
43969 this.setActivePanel(panel);
43975 * Get the active panel for this region.
43976 * @return {Roo.ContentPanel} The active panel or null
43978 getActivePanel : function(){
43979 return this.activePanel;
43983 * Add the passed ContentPanel(s)
43984 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43985 * @return {Roo.ContentPanel} The panel added (if only one was added)
43987 add : function(panel){
43988 if(arguments.length > 1){
43989 for(var i = 0, len = arguments.length; i < len; i++) {
43990 this.add(arguments[i]);
43994 if(this.hasPanel(panel)){
43995 this.showPanel(panel);
43998 var el = panel.getEl();
43999 if(el.dom.parentNode != this.mgr.el.dom){
44000 this.mgr.el.dom.appendChild(el.dom);
44002 if(panel.setRegion){
44003 panel.setRegion(this);
44005 this.panels.add(panel);
44006 el.setStyle("position", "absolute");
44007 if(!panel.background){
44008 this.setActivePanel(panel);
44009 if(this.config.initialSize && this.panels.getCount()==1){
44010 this.resizeTo(this.config.initialSize);
44013 this.fireEvent("paneladded", this, panel);
44018 * Returns true if the panel is in this region.
44019 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44020 * @return {Boolean}
44022 hasPanel : function(panel){
44023 if(typeof panel == "object"){ // must be panel obj
44024 panel = panel.getId();
44026 return this.getPanel(panel) ? true : false;
44030 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44031 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44032 * @param {Boolean} preservePanel Overrides the config preservePanel option
44033 * @return {Roo.ContentPanel} The panel that was removed
44035 remove : function(panel, preservePanel){
44036 panel = this.getPanel(panel);
44041 this.fireEvent("beforeremove", this, panel, e);
44042 if(e.cancel === true){
44045 var panelId = panel.getId();
44046 this.panels.removeKey(panelId);
44051 * Returns the panel specified or null if it's not in this region.
44052 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44053 * @return {Roo.ContentPanel}
44055 getPanel : function(id){
44056 if(typeof id == "object"){ // must be panel obj
44059 return this.panels.get(id);
44063 * Returns this regions position (north/south/east/west/center).
44066 getPosition: function(){
44067 return this.position;
44071 * Ext JS Library 1.1.1
44072 * Copyright(c) 2006-2007, Ext JS, LLC.
44074 * Originally Released Under LGPL - original licence link has changed is not relivant.
44077 * <script type="text/javascript">
44081 * @class Roo.LayoutRegion
44082 * @extends Roo.BasicLayoutRegion
44083 * This class represents a region in a layout manager.
44084 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44085 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44086 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44087 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44088 * @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})
44089 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44090 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44091 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44092 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44093 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44094 * @cfg {String} title The title for the region (overrides panel titles)
44095 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44096 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44097 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44098 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44099 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44100 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44101 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44102 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44103 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44104 * @cfg {Boolean} showPin True to show a pin button
44105 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44106 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44107 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44108 * @cfg {Number} width For East/West panels
44109 * @cfg {Number} height For North/South panels
44110 * @cfg {Boolean} split To show the splitter
44112 Roo.LayoutRegion = function(mgr, config, pos){
44113 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44114 var dh = Roo.DomHelper;
44115 /** This region's container element
44116 * @type Roo.Element */
44117 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44118 /** This region's title element
44119 * @type Roo.Element */
44121 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44122 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44123 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44125 this.titleEl.enableDisplayMode();
44126 /** This region's title text element
44127 * @type HTMLElement */
44128 this.titleTextEl = this.titleEl.dom.firstChild;
44129 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44130 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44131 this.closeBtn.enableDisplayMode();
44132 this.closeBtn.on("click", this.closeClicked, this);
44133 this.closeBtn.hide();
44135 this.createBody(config);
44136 this.visible = true;
44137 this.collapsed = false;
44139 if(config.hideWhenEmpty){
44141 this.on("paneladded", this.validateVisibility, this);
44142 this.on("panelremoved", this.validateVisibility, this);
44144 this.applyConfig(config);
44147 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44149 createBody : function(){
44150 /** This region's body element
44151 * @type Roo.Element */
44152 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44155 applyConfig : function(c){
44156 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44157 var dh = Roo.DomHelper;
44158 if(c.titlebar !== false){
44159 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44160 this.collapseBtn.on("click", this.collapse, this);
44161 this.collapseBtn.enableDisplayMode();
44163 if(c.showPin === true || this.showPin){
44164 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44165 this.stickBtn.enableDisplayMode();
44166 this.stickBtn.on("click", this.expand, this);
44167 this.stickBtn.hide();
44170 /** This region's collapsed element
44171 * @type Roo.Element */
44172 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44173 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44175 if(c.floatable !== false){
44176 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44177 this.collapsedEl.on("click", this.collapseClick, this);
44180 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44181 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44182 id: "message", unselectable: "on", style:{"float":"left"}});
44183 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44185 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44186 this.expandBtn.on("click", this.expand, this);
44188 if(this.collapseBtn){
44189 this.collapseBtn.setVisible(c.collapsible == true);
44191 this.cmargins = c.cmargins || this.cmargins ||
44192 (this.position == "west" || this.position == "east" ?
44193 {top: 0, left: 2, right:2, bottom: 0} :
44194 {top: 2, left: 0, right:0, bottom: 2});
44195 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44196 this.bottomTabs = c.tabPosition != "top";
44197 this.autoScroll = c.autoScroll || false;
44198 if(this.autoScroll){
44199 this.bodyEl.setStyle("overflow", "auto");
44201 this.bodyEl.setStyle("overflow", "hidden");
44203 //if(c.titlebar !== false){
44204 if((!c.titlebar && !c.title) || c.titlebar === false){
44205 this.titleEl.hide();
44207 this.titleEl.show();
44209 this.titleTextEl.innerHTML = c.title;
44213 this.duration = c.duration || .30;
44214 this.slideDuration = c.slideDuration || .45;
44217 this.collapse(true);
44224 * Returns true if this region is currently visible.
44225 * @return {Boolean}
44227 isVisible : function(){
44228 return this.visible;
44232 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44233 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44235 setCollapsedTitle : function(title){
44236 title = title || " ";
44237 if(this.collapsedTitleTextEl){
44238 this.collapsedTitleTextEl.innerHTML = title;
44242 getBox : function(){
44244 if(!this.collapsed){
44245 b = this.el.getBox(false, true);
44247 b = this.collapsedEl.getBox(false, true);
44252 getMargins : function(){
44253 return this.collapsed ? this.cmargins : this.margins;
44256 highlight : function(){
44257 this.el.addClass("x-layout-panel-dragover");
44260 unhighlight : function(){
44261 this.el.removeClass("x-layout-panel-dragover");
44264 updateBox : function(box){
44266 if(!this.collapsed){
44267 this.el.dom.style.left = box.x + "px";
44268 this.el.dom.style.top = box.y + "px";
44269 this.updateBody(box.width, box.height);
44271 this.collapsedEl.dom.style.left = box.x + "px";
44272 this.collapsedEl.dom.style.top = box.y + "px";
44273 this.collapsedEl.setSize(box.width, box.height);
44276 this.tabs.autoSizeTabs();
44280 updateBody : function(w, h){
44282 this.el.setWidth(w);
44283 w -= this.el.getBorderWidth("rl");
44284 if(this.config.adjustments){
44285 w += this.config.adjustments[0];
44289 this.el.setHeight(h);
44290 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44291 h -= this.el.getBorderWidth("tb");
44292 if(this.config.adjustments){
44293 h += this.config.adjustments[1];
44295 this.bodyEl.setHeight(h);
44297 h = this.tabs.syncHeight(h);
44300 if(this.panelSize){
44301 w = w !== null ? w : this.panelSize.width;
44302 h = h !== null ? h : this.panelSize.height;
44304 if(this.activePanel){
44305 var el = this.activePanel.getEl();
44306 w = w !== null ? w : el.getWidth();
44307 h = h !== null ? h : el.getHeight();
44308 this.panelSize = {width: w, height: h};
44309 this.activePanel.setSize(w, h);
44311 if(Roo.isIE && this.tabs){
44312 this.tabs.el.repaint();
44317 * Returns the container element for this region.
44318 * @return {Roo.Element}
44320 getEl : function(){
44325 * Hides this region.
44328 if(!this.collapsed){
44329 this.el.dom.style.left = "-2000px";
44332 this.collapsedEl.dom.style.left = "-2000px";
44333 this.collapsedEl.hide();
44335 this.visible = false;
44336 this.fireEvent("visibilitychange", this, false);
44340 * Shows this region if it was previously hidden.
44343 if(!this.collapsed){
44346 this.collapsedEl.show();
44348 this.visible = true;
44349 this.fireEvent("visibilitychange", this, true);
44352 closeClicked : function(){
44353 if(this.activePanel){
44354 this.remove(this.activePanel);
44358 collapseClick : function(e){
44360 e.stopPropagation();
44363 e.stopPropagation();
44369 * Collapses this region.
44370 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44372 collapse : function(skipAnim){
44373 if(this.collapsed) return;
44374 this.collapsed = true;
44376 this.split.el.hide();
44378 if(this.config.animate && skipAnim !== true){
44379 this.fireEvent("invalidated", this);
44380 this.animateCollapse();
44382 this.el.setLocation(-20000,-20000);
44384 this.collapsedEl.show();
44385 this.fireEvent("collapsed", this);
44386 this.fireEvent("invalidated", this);
44390 animateCollapse : function(){
44395 * Expands this region if it was previously collapsed.
44396 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44397 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44399 expand : function(e, skipAnim){
44400 if(e) e.stopPropagation();
44401 if(!this.collapsed || this.el.hasActiveFx()) return;
44403 this.afterSlideIn();
44406 this.collapsed = false;
44407 if(this.config.animate && skipAnim !== true){
44408 this.animateExpand();
44412 this.split.el.show();
44414 this.collapsedEl.setLocation(-2000,-2000);
44415 this.collapsedEl.hide();
44416 this.fireEvent("invalidated", this);
44417 this.fireEvent("expanded", this);
44421 animateExpand : function(){
44425 initTabs : function(){
44426 this.bodyEl.setStyle("overflow", "hidden");
44427 var ts = new Roo.TabPanel(this.bodyEl.dom, {
44428 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44429 disableTooltips: this.config.disableTabTips
44431 if(this.config.hideTabs){
44432 ts.stripWrap.setDisplayed(false);
44435 ts.resizeTabs = this.config.resizeTabs === true;
44436 ts.minTabWidth = this.config.minTabWidth || 40;
44437 ts.maxTabWidth = this.config.maxTabWidth || 250;
44438 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44439 ts.monitorResize = false;
44440 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44441 ts.bodyEl.addClass('x-layout-tabs-body');
44442 this.panels.each(this.initPanelAsTab, this);
44445 initPanelAsTab : function(panel){
44446 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44447 this.config.closeOnTab && panel.isClosable());
44448 if(panel.tabTip !== undefined){
44449 ti.setTooltip(panel.tabTip);
44451 ti.on("activate", function(){
44452 this.setActivePanel(panel);
44454 if(this.config.closeOnTab){
44455 ti.on("beforeclose", function(t, e){
44457 this.remove(panel);
44463 updatePanelTitle : function(panel, title){
44464 if(this.activePanel == panel){
44465 this.updateTitle(title);
44468 var ti = this.tabs.getTab(panel.getEl().id);
44470 if(panel.tabTip !== undefined){
44471 ti.setTooltip(panel.tabTip);
44476 updateTitle : function(title){
44477 if(this.titleTextEl && !this.config.title){
44478 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44482 setActivePanel : function(panel){
44483 panel = this.getPanel(panel);
44484 if(this.activePanel && this.activePanel != panel){
44485 this.activePanel.setActiveState(false);
44487 this.activePanel = panel;
44488 panel.setActiveState(true);
44489 if(this.panelSize){
44490 panel.setSize(this.panelSize.width, this.panelSize.height);
44493 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44495 this.updateTitle(panel.getTitle());
44497 this.fireEvent("invalidated", this);
44499 this.fireEvent("panelactivated", this, panel);
44503 * Shows the specified panel.
44504 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44505 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44507 showPanel : function(panel){
44508 if(panel = this.getPanel(panel)){
44510 var tab = this.tabs.getTab(panel.getEl().id);
44511 if(tab.isHidden()){
44512 this.tabs.unhideTab(tab.id);
44516 this.setActivePanel(panel);
44523 * Get the active panel for this region.
44524 * @return {Roo.ContentPanel} The active panel or null
44526 getActivePanel : function(){
44527 return this.activePanel;
44530 validateVisibility : function(){
44531 if(this.panels.getCount() < 1){
44532 this.updateTitle(" ");
44533 this.closeBtn.hide();
44536 if(!this.isVisible()){
44543 * Adds the passed ContentPanel(s) to this region.
44544 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44545 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44547 add : function(panel){
44548 if(arguments.length > 1){
44549 for(var i = 0, len = arguments.length; i < len; i++) {
44550 this.add(arguments[i]);
44554 if(this.hasPanel(panel)){
44555 this.showPanel(panel);
44558 panel.setRegion(this);
44559 this.panels.add(panel);
44560 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44561 this.bodyEl.dom.appendChild(panel.getEl().dom);
44562 if(panel.background !== true){
44563 this.setActivePanel(panel);
44565 this.fireEvent("paneladded", this, panel);
44571 this.initPanelAsTab(panel);
44573 if(panel.background !== true){
44574 this.tabs.activate(panel.getEl().id);
44576 this.fireEvent("paneladded", this, panel);
44581 * Hides the tab for the specified panel.
44582 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44584 hidePanel : function(panel){
44585 if(this.tabs && (panel = this.getPanel(panel))){
44586 this.tabs.hideTab(panel.getEl().id);
44591 * Unhides the tab for a previously hidden panel.
44592 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44594 unhidePanel : function(panel){
44595 if(this.tabs && (panel = this.getPanel(panel))){
44596 this.tabs.unhideTab(panel.getEl().id);
44600 clearPanels : function(){
44601 while(this.panels.getCount() > 0){
44602 this.remove(this.panels.first());
44607 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44608 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44609 * @param {Boolean} preservePanel Overrides the config preservePanel option
44610 * @return {Roo.ContentPanel} The panel that was removed
44612 remove : function(panel, preservePanel){
44613 panel = this.getPanel(panel);
44618 this.fireEvent("beforeremove", this, panel, e);
44619 if(e.cancel === true){
44622 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44623 var panelId = panel.getId();
44624 this.panels.removeKey(panelId);
44626 document.body.appendChild(panel.getEl().dom);
44629 this.tabs.removeTab(panel.getEl().id);
44630 }else if (!preservePanel){
44631 this.bodyEl.dom.removeChild(panel.getEl().dom);
44633 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44634 var p = this.panels.first();
44635 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44636 tempEl.appendChild(p.getEl().dom);
44637 this.bodyEl.update("");
44638 this.bodyEl.dom.appendChild(p.getEl().dom);
44640 this.updateTitle(p.getTitle());
44642 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44643 this.setActivePanel(p);
44645 panel.setRegion(null);
44646 if(this.activePanel == panel){
44647 this.activePanel = null;
44649 if(this.config.autoDestroy !== false && preservePanel !== true){
44650 try{panel.destroy();}catch(e){}
44652 this.fireEvent("panelremoved", this, panel);
44657 * Returns the TabPanel component used by this region
44658 * @return {Roo.TabPanel}
44660 getTabs : function(){
44664 createTool : function(parentEl, className){
44665 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44666 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44667 btn.addClassOnOver("x-layout-tools-button-over");
44672 * Ext JS Library 1.1.1
44673 * Copyright(c) 2006-2007, Ext JS, LLC.
44675 * Originally Released Under LGPL - original licence link has changed is not relivant.
44678 * <script type="text/javascript">
44684 * @class Roo.SplitLayoutRegion
44685 * @extends Roo.LayoutRegion
44686 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44688 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
44689 this.cursor = cursor;
44690 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
44693 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
44694 splitTip : "Drag to resize.",
44695 collapsibleSplitTip : "Drag to resize. Double click to hide.",
44696 useSplitTips : false,
44698 applyConfig : function(config){
44699 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
44702 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
44703 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
44704 /** The SplitBar for this region
44705 * @type Roo.SplitBar */
44706 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
44707 this.split.on("moved", this.onSplitMove, this);
44708 this.split.useShim = config.useShim === true;
44709 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
44710 if(this.useSplitTips){
44711 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
44713 if(config.collapsible){
44714 this.split.el.on("dblclick", this.collapse, this);
44717 if(typeof config.minSize != "undefined"){
44718 this.split.minSize = config.minSize;
44720 if(typeof config.maxSize != "undefined"){
44721 this.split.maxSize = config.maxSize;
44723 if(config.hideWhenEmpty || config.hidden || config.collapsed){
44724 this.hideSplitter();
44729 getHMaxSize : function(){
44730 var cmax = this.config.maxSize || 10000;
44731 var center = this.mgr.getRegion("center");
44732 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
44735 getVMaxSize : function(){
44736 var cmax = this.config.maxSize || 10000;
44737 var center = this.mgr.getRegion("center");
44738 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
44741 onSplitMove : function(split, newSize){
44742 this.fireEvent("resized", this, newSize);
44746 * Returns the {@link Roo.SplitBar} for this region.
44747 * @return {Roo.SplitBar}
44749 getSplitBar : function(){
44754 this.hideSplitter();
44755 Roo.SplitLayoutRegion.superclass.hide.call(this);
44758 hideSplitter : function(){
44760 this.split.el.setLocation(-2000,-2000);
44761 this.split.el.hide();
44767 this.split.el.show();
44769 Roo.SplitLayoutRegion.superclass.show.call(this);
44772 beforeSlide: function(){
44773 if(Roo.isGecko){// firefox overflow auto bug workaround
44774 this.bodyEl.clip();
44775 if(this.tabs) this.tabs.bodyEl.clip();
44776 if(this.activePanel){
44777 this.activePanel.getEl().clip();
44779 if(this.activePanel.beforeSlide){
44780 this.activePanel.beforeSlide();
44786 afterSlide : function(){
44787 if(Roo.isGecko){// firefox overflow auto bug workaround
44788 this.bodyEl.unclip();
44789 if(this.tabs) this.tabs.bodyEl.unclip();
44790 if(this.activePanel){
44791 this.activePanel.getEl().unclip();
44792 if(this.activePanel.afterSlide){
44793 this.activePanel.afterSlide();
44799 initAutoHide : function(){
44800 if(this.autoHide !== false){
44801 if(!this.autoHideHd){
44802 var st = new Roo.util.DelayedTask(this.slideIn, this);
44803 this.autoHideHd = {
44804 "mouseout": function(e){
44805 if(!e.within(this.el, true)){
44809 "mouseover" : function(e){
44815 this.el.on(this.autoHideHd);
44819 clearAutoHide : function(){
44820 if(this.autoHide !== false){
44821 this.el.un("mouseout", this.autoHideHd.mouseout);
44822 this.el.un("mouseover", this.autoHideHd.mouseover);
44826 clearMonitor : function(){
44827 Roo.get(document).un("click", this.slideInIf, this);
44830 // these names are backwards but not changed for compat
44831 slideOut : function(){
44832 if(this.isSlid || this.el.hasActiveFx()){
44835 this.isSlid = true;
44836 if(this.collapseBtn){
44837 this.collapseBtn.hide();
44839 this.closeBtnState = this.closeBtn.getStyle('display');
44840 this.closeBtn.hide();
44842 this.stickBtn.show();
44845 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
44846 this.beforeSlide();
44847 this.el.setStyle("z-index", 10001);
44848 this.el.slideIn(this.getSlideAnchor(), {
44849 callback: function(){
44851 this.initAutoHide();
44852 Roo.get(document).on("click", this.slideInIf, this);
44853 this.fireEvent("slideshow", this);
44860 afterSlideIn : function(){
44861 this.clearAutoHide();
44862 this.isSlid = false;
44863 this.clearMonitor();
44864 this.el.setStyle("z-index", "");
44865 if(this.collapseBtn){
44866 this.collapseBtn.show();
44868 this.closeBtn.setStyle('display', this.closeBtnState);
44870 this.stickBtn.hide();
44872 this.fireEvent("slidehide", this);
44875 slideIn : function(cb){
44876 if(!this.isSlid || this.el.hasActiveFx()){
44880 this.isSlid = false;
44881 this.beforeSlide();
44882 this.el.slideOut(this.getSlideAnchor(), {
44883 callback: function(){
44884 this.el.setLeftTop(-10000, -10000);
44886 this.afterSlideIn();
44894 slideInIf : function(e){
44895 if(!e.within(this.el)){
44900 animateCollapse : function(){
44901 this.beforeSlide();
44902 this.el.setStyle("z-index", 20000);
44903 var anchor = this.getSlideAnchor();
44904 this.el.slideOut(anchor, {
44905 callback : function(){
44906 this.el.setStyle("z-index", "");
44907 this.collapsedEl.slideIn(anchor, {duration:.3});
44909 this.el.setLocation(-10000,-10000);
44911 this.fireEvent("collapsed", this);
44918 animateExpand : function(){
44919 this.beforeSlide();
44920 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
44921 this.el.setStyle("z-index", 20000);
44922 this.collapsedEl.hide({
44925 this.el.slideIn(this.getSlideAnchor(), {
44926 callback : function(){
44927 this.el.setStyle("z-index", "");
44930 this.split.el.show();
44932 this.fireEvent("invalidated", this);
44933 this.fireEvent("expanded", this);
44961 getAnchor : function(){
44962 return this.anchors[this.position];
44965 getCollapseAnchor : function(){
44966 return this.canchors[this.position];
44969 getSlideAnchor : function(){
44970 return this.sanchors[this.position];
44973 getAlignAdj : function(){
44974 var cm = this.cmargins;
44975 switch(this.position){
44991 getExpandAdj : function(){
44992 var c = this.collapsedEl, cm = this.cmargins;
44993 switch(this.position){
44995 return [-(cm.right+c.getWidth()+cm.left), 0];
44998 return [cm.right+c.getWidth()+cm.left, 0];
45001 return [0, -(cm.top+cm.bottom+c.getHeight())];
45004 return [0, cm.top+cm.bottom+c.getHeight()];
45010 * Ext JS Library 1.1.1
45011 * Copyright(c) 2006-2007, Ext JS, LLC.
45013 * Originally Released Under LGPL - original licence link has changed is not relivant.
45016 * <script type="text/javascript">
45019 * These classes are private internal classes
45021 Roo.CenterLayoutRegion = function(mgr, config){
45022 Roo.LayoutRegion.call(this, mgr, config, "center");
45023 this.visible = true;
45024 this.minWidth = config.minWidth || 20;
45025 this.minHeight = config.minHeight || 20;
45028 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45030 // center panel can't be hidden
45034 // center panel can't be hidden
45037 getMinWidth: function(){
45038 return this.minWidth;
45041 getMinHeight: function(){
45042 return this.minHeight;
45047 Roo.NorthLayoutRegion = function(mgr, config){
45048 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45050 this.split.placement = Roo.SplitBar.TOP;
45051 this.split.orientation = Roo.SplitBar.VERTICAL;
45052 this.split.el.addClass("x-layout-split-v");
45054 var size = config.initialSize || config.height;
45055 if(typeof size != "undefined"){
45056 this.el.setHeight(size);
45059 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45060 orientation: Roo.SplitBar.VERTICAL,
45061 getBox : function(){
45062 if(this.collapsed){
45063 return this.collapsedEl.getBox();
45065 var box = this.el.getBox();
45067 box.height += this.split.el.getHeight();
45072 updateBox : function(box){
45073 if(this.split && !this.collapsed){
45074 box.height -= this.split.el.getHeight();
45075 this.split.el.setLeft(box.x);
45076 this.split.el.setTop(box.y+box.height);
45077 this.split.el.setWidth(box.width);
45079 if(this.collapsed){
45080 this.updateBody(box.width, null);
45082 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45086 Roo.SouthLayoutRegion = function(mgr, config){
45087 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45089 this.split.placement = Roo.SplitBar.BOTTOM;
45090 this.split.orientation = Roo.SplitBar.VERTICAL;
45091 this.split.el.addClass("x-layout-split-v");
45093 var size = config.initialSize || config.height;
45094 if(typeof size != "undefined"){
45095 this.el.setHeight(size);
45098 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45099 orientation: Roo.SplitBar.VERTICAL,
45100 getBox : function(){
45101 if(this.collapsed){
45102 return this.collapsedEl.getBox();
45104 var box = this.el.getBox();
45106 var sh = this.split.el.getHeight();
45113 updateBox : function(box){
45114 if(this.split && !this.collapsed){
45115 var sh = this.split.el.getHeight();
45118 this.split.el.setLeft(box.x);
45119 this.split.el.setTop(box.y-sh);
45120 this.split.el.setWidth(box.width);
45122 if(this.collapsed){
45123 this.updateBody(box.width, null);
45125 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45129 Roo.EastLayoutRegion = function(mgr, config){
45130 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45132 this.split.placement = Roo.SplitBar.RIGHT;
45133 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45134 this.split.el.addClass("x-layout-split-h");
45136 var size = config.initialSize || config.width;
45137 if(typeof size != "undefined"){
45138 this.el.setWidth(size);
45141 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45142 orientation: Roo.SplitBar.HORIZONTAL,
45143 getBox : function(){
45144 if(this.collapsed){
45145 return this.collapsedEl.getBox();
45147 var box = this.el.getBox();
45149 var sw = this.split.el.getWidth();
45156 updateBox : function(box){
45157 if(this.split && !this.collapsed){
45158 var sw = this.split.el.getWidth();
45160 this.split.el.setLeft(box.x);
45161 this.split.el.setTop(box.y);
45162 this.split.el.setHeight(box.height);
45165 if(this.collapsed){
45166 this.updateBody(null, box.height);
45168 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45172 Roo.WestLayoutRegion = function(mgr, config){
45173 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45175 this.split.placement = Roo.SplitBar.LEFT;
45176 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45177 this.split.el.addClass("x-layout-split-h");
45179 var size = config.initialSize || config.width;
45180 if(typeof size != "undefined"){
45181 this.el.setWidth(size);
45184 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45185 orientation: Roo.SplitBar.HORIZONTAL,
45186 getBox : function(){
45187 if(this.collapsed){
45188 return this.collapsedEl.getBox();
45190 var box = this.el.getBox();
45192 box.width += this.split.el.getWidth();
45197 updateBox : function(box){
45198 if(this.split && !this.collapsed){
45199 var sw = this.split.el.getWidth();
45201 this.split.el.setLeft(box.x+box.width);
45202 this.split.el.setTop(box.y);
45203 this.split.el.setHeight(box.height);
45205 if(this.collapsed){
45206 this.updateBody(null, box.height);
45208 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45213 * Ext JS Library 1.1.1
45214 * Copyright(c) 2006-2007, Ext JS, LLC.
45216 * Originally Released Under LGPL - original licence link has changed is not relivant.
45219 * <script type="text/javascript">
45224 * Private internal class for reading and applying state
45226 Roo.LayoutStateManager = function(layout){
45227 // default empty state
45236 Roo.LayoutStateManager.prototype = {
45237 init : function(layout, provider){
45238 this.provider = provider;
45239 var state = provider.get(layout.id+"-layout-state");
45241 var wasUpdating = layout.isUpdating();
45243 layout.beginUpdate();
45245 for(var key in state){
45246 if(typeof state[key] != "function"){
45247 var rstate = state[key];
45248 var r = layout.getRegion(key);
45251 r.resizeTo(rstate.size);
45253 if(rstate.collapsed == true){
45256 r.expand(null, true);
45262 layout.endUpdate();
45264 this.state = state;
45266 this.layout = layout;
45267 layout.on("regionresized", this.onRegionResized, this);
45268 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45269 layout.on("regionexpanded", this.onRegionExpanded, this);
45272 storeState : function(){
45273 this.provider.set(this.layout.id+"-layout-state", this.state);
45276 onRegionResized : function(region, newSize){
45277 this.state[region.getPosition()].size = newSize;
45281 onRegionCollapsed : function(region){
45282 this.state[region.getPosition()].collapsed = true;
45286 onRegionExpanded : function(region){
45287 this.state[region.getPosition()].collapsed = false;
45292 * Ext JS Library 1.1.1
45293 * Copyright(c) 2006-2007, Ext JS, LLC.
45295 * Originally Released Under LGPL - original licence link has changed is not relivant.
45298 * <script type="text/javascript">
45301 * @class Roo.ContentPanel
45302 * @extends Roo.util.Observable
45303 * A basic ContentPanel element.
45304 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45305 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45306 * @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
45307 * @cfg {Boolean} closable True if the panel can be closed/removed
45308 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45309 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45310 * @cfg {Toolbar} toolbar A toolbar for this panel
45311 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45312 * @cfg {String} title The title for this panel
45313 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45314 * @cfg {String} url Calls {@link #setUrl} with this value
45315 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45316 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45317 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45319 * Create a new ContentPanel.
45320 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45321 * @param {String/Object} config A string to set only the title or a config object
45322 * @param {String} content (optional) Set the HTML content for this panel
45323 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45325 Roo.ContentPanel = function(el, config, content){
45329 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45333 if (config && config.parentLayout) {
45334 el = config.parentLayout.el.createChild();
45337 if(el.autoCreate){ // xtype is available if this is called from factory
45341 this.el = Roo.get(el);
45342 if(!this.el && config && config.autoCreate){
45343 if(typeof config.autoCreate == "object"){
45344 if(!config.autoCreate.id){
45345 config.autoCreate.id = config.id||el;
45347 this.el = Roo.DomHelper.append(document.body,
45348 config.autoCreate, true);
45350 this.el = Roo.DomHelper.append(document.body,
45351 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45354 this.closable = false;
45355 this.loaded = false;
45356 this.active = false;
45357 if(typeof config == "string"){
45358 this.title = config;
45360 Roo.apply(this, config);
45363 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45364 this.wrapEl = this.el.wrap();
45365 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45372 this.resizeEl = Roo.get(this.resizeEl, true);
45374 this.resizeEl = this.el;
45379 * Fires when this panel is activated.
45380 * @param {Roo.ContentPanel} this
45384 * @event deactivate
45385 * Fires when this panel is activated.
45386 * @param {Roo.ContentPanel} this
45388 "deactivate" : true,
45392 * Fires when this panel is resized if fitToFrame is true.
45393 * @param {Roo.ContentPanel} this
45394 * @param {Number} width The width after any component adjustments
45395 * @param {Number} height The height after any component adjustments
45399 if(this.autoScroll){
45400 this.resizeEl.setStyle("overflow", "auto");
45402 // fix randome scrolling
45403 this.el.on('scroll', function() {
45404 this.scrollTo('top',0);
45407 content = content || this.content;
45409 this.setContent(content);
45411 if(config && config.url){
45412 this.setUrl(this.url, this.params, this.loadOnce);
45417 Roo.ContentPanel.superclass.constructor.call(this);
45420 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45422 setRegion : function(region){
45423 this.region = region;
45425 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45427 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45432 * Returns the toolbar for this Panel if one was configured.
45433 * @return {Roo.Toolbar}
45435 getToolbar : function(){
45436 return this.toolbar;
45439 setActiveState : function(active){
45440 this.active = active;
45442 this.fireEvent("deactivate", this);
45444 this.fireEvent("activate", this);
45448 * Updates this panel's element
45449 * @param {String} content The new content
45450 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45452 setContent : function(content, loadScripts){
45453 this.el.update(content, loadScripts);
45456 ignoreResize : function(w, h){
45457 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45460 this.lastSize = {width: w, height: h};
45465 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45466 * @return {Roo.UpdateManager} The UpdateManager
45468 getUpdateManager : function(){
45469 return this.el.getUpdateManager();
45472 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45473 * @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:
45476 url: "your-url.php",
45477 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45478 callback: yourFunction,
45479 scope: yourObject, //(optional scope)
45482 text: "Loading...",
45487 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45488 * 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.
45489 * @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}
45490 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45491 * @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.
45492 * @return {Roo.ContentPanel} this
45495 var um = this.el.getUpdateManager();
45496 um.update.apply(um, arguments);
45502 * 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.
45503 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45504 * @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)
45505 * @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)
45506 * @return {Roo.UpdateManager} The UpdateManager
45508 setUrl : function(url, params, loadOnce){
45509 if(this.refreshDelegate){
45510 this.removeListener("activate", this.refreshDelegate);
45512 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45513 this.on("activate", this.refreshDelegate);
45514 return this.el.getUpdateManager();
45517 _handleRefresh : function(url, params, loadOnce){
45518 if(!loadOnce || !this.loaded){
45519 var updater = this.el.getUpdateManager();
45520 updater.update(url, params, this._setLoaded.createDelegate(this));
45524 _setLoaded : function(){
45525 this.loaded = true;
45529 * Returns this panel's id
45532 getId : function(){
45537 * Returns this panel's element - used by regiosn to add.
45538 * @return {Roo.Element}
45540 getEl : function(){
45541 return this.wrapEl || this.el;
45544 adjustForComponents : function(width, height){
45545 if(this.resizeEl != this.el){
45546 width -= this.el.getFrameWidth('lr');
45547 height -= this.el.getFrameWidth('tb');
45550 var te = this.toolbar.getEl();
45551 height -= te.getHeight();
45552 te.setWidth(width);
45554 if(this.adjustments){
45555 width += this.adjustments[0];
45556 height += this.adjustments[1];
45558 return {"width": width, "height": height};
45561 setSize : function(width, height){
45562 if(this.fitToFrame && !this.ignoreResize(width, height)){
45563 if(this.fitContainer && this.resizeEl != this.el){
45564 this.el.setSize(width, height);
45566 var size = this.adjustForComponents(width, height);
45567 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45568 this.fireEvent('resize', this, size.width, size.height);
45573 * Returns this panel's title
45576 getTitle : function(){
45581 * Set this panel's title
45582 * @param {String} title
45584 setTitle : function(title){
45585 this.title = title;
45587 this.region.updatePanelTitle(this, title);
45592 * Returns true is this panel was configured to be closable
45593 * @return {Boolean}
45595 isClosable : function(){
45596 return this.closable;
45599 beforeSlide : function(){
45601 this.resizeEl.clip();
45604 afterSlide : function(){
45606 this.resizeEl.unclip();
45610 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45611 * Will fail silently if the {@link #setUrl} method has not been called.
45612 * This does not activate the panel, just updates its content.
45614 refresh : function(){
45615 if(this.refreshDelegate){
45616 this.loaded = false;
45617 this.refreshDelegate();
45622 * Destroys this panel
45624 destroy : function(){
45625 this.el.removeAllListeners();
45626 var tempEl = document.createElement("span");
45627 tempEl.appendChild(this.el.dom);
45628 tempEl.innerHTML = "";
45634 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45644 * @param {Object} cfg Xtype definition of item to add.
45647 addxtype : function(cfg) {
45649 if (cfg.xtype.match(/^Form$/)) {
45650 var el = this.el.createChild();
45652 this.form = new Roo.form.Form(cfg);
45655 if ( this.form.allItems.length) this.form.render(el.dom);
45658 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
45660 cfg.el = this.el.appendChild(document.createElement("div"));
45662 var ret = new Roo[cfg.xtype](cfg);
45663 ret.render(false, ''); // render blank..
45673 * @class Roo.GridPanel
45674 * @extends Roo.ContentPanel
45676 * Create a new GridPanel.
45677 * @param {Roo.grid.Grid} grid The grid for this panel
45678 * @param {String/Object} config A string to set only the panel's title, or a config object
45680 Roo.GridPanel = function(grid, config){
45683 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45684 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45686 this.wrapper.dom.appendChild(grid.getGridEl().dom);
45688 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
45691 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
45693 // xtype created footer. - not sure if will work as we normally have to render first..
45694 if (this.footer && !this.footer.el && this.footer.xtype) {
45696 this.footer.container = this.grid.getView().getFooterPanel(true);
45697 this.footer.dataSource = this.grid.dataSource;
45698 this.footer = Roo.factory(this.footer, Roo);
45702 grid.monitorWindowResize = false; // turn off autosizing
45703 grid.autoHeight = false;
45704 grid.autoWidth = false;
45706 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
45709 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
45710 getId : function(){
45711 return this.grid.id;
45715 * Returns the grid for this panel
45716 * @return {Roo.grid.Grid}
45718 getGrid : function(){
45722 setSize : function(width, height){
45723 if(!this.ignoreResize(width, height)){
45724 var grid = this.grid;
45725 var size = this.adjustForComponents(width, height);
45726 grid.getGridEl().setSize(size.width, size.height);
45731 beforeSlide : function(){
45732 this.grid.getView().scroller.clip();
45735 afterSlide : function(){
45736 this.grid.getView().scroller.unclip();
45739 destroy : function(){
45740 this.grid.destroy();
45742 Roo.GridPanel.superclass.destroy.call(this);
45748 * @class Roo.NestedLayoutPanel
45749 * @extends Roo.ContentPanel
45751 * Create a new NestedLayoutPanel.
45754 * @param {Roo.BorderLayout} layout The layout for this panel
45755 * @param {String/Object} config A string to set only the title or a config object
45757 Roo.NestedLayoutPanel = function(layout, config)
45759 // construct with only one argument..
45760 /* FIXME - implement nicer consturctors
45761 if (layout.layout) {
45763 layout = config.layout;
45764 delete config.layout;
45766 if (layout.xtype && !layout.getEl) {
45767 // then layout needs constructing..
45768 layout = Roo.factory(layout, Roo);
45773 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
45775 layout.monitorWindowResize = false; // turn off autosizing
45776 this.layout = layout;
45777 this.layout.getEl().addClass("x-layout-nested-layout");
45784 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
45786 setSize : function(width, height){
45787 if(!this.ignoreResize(width, height)){
45788 var size = this.adjustForComponents(width, height);
45789 var el = this.layout.getEl();
45790 el.setSize(size.width, size.height);
45791 var touch = el.dom.offsetWidth;
45792 this.layout.layout();
45793 // ie requires a double layout on the first pass
45794 if(Roo.isIE && !this.initialized){
45795 this.initialized = true;
45796 this.layout.layout();
45801 // activate all subpanels if not currently active..
45803 setActiveState : function(active){
45804 this.active = active;
45806 this.fireEvent("deactivate", this);
45810 this.fireEvent("activate", this);
45811 // not sure if this should happen before or after..
45812 if (!this.layout) {
45813 return; // should not happen..
45816 for (var r in this.layout.regions) {
45817 reg = this.layout.getRegion(r);
45818 if (reg.getActivePanel()) {
45819 //reg.showPanel(reg.getActivePanel()); // force it to activate..
45820 reg.setActivePanel(reg.getActivePanel());
45823 if (!reg.panels.length) {
45826 reg.showPanel(reg.getPanel(0));
45835 * Returns the nested BorderLayout for this panel
45836 * @return {Roo.BorderLayout}
45838 getLayout : function(){
45839 return this.layout;
45843 * Adds a xtype elements to the layout of the nested panel
45847 xtype : 'ContentPanel',
45854 xtype : 'NestedLayoutPanel',
45860 items : [ ... list of content panels or nested layout panels.. ]
45864 * @param {Object} cfg Xtype definition of item to add.
45866 addxtype : function(cfg) {
45867 return this.layout.addxtype(cfg);
45872 Roo.ScrollPanel = function(el, config, content){
45873 config = config || {};
45874 config.fitToFrame = true;
45875 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
45877 this.el.dom.style.overflow = "hidden";
45878 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
45879 this.el.removeClass("x-layout-inactive-content");
45880 this.el.on("mousewheel", this.onWheel, this);
45882 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
45883 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
45884 up.unselectable(); down.unselectable();
45885 up.on("click", this.scrollUp, this);
45886 down.on("click", this.scrollDown, this);
45887 up.addClassOnOver("x-scroller-btn-over");
45888 down.addClassOnOver("x-scroller-btn-over");
45889 up.addClassOnClick("x-scroller-btn-click");
45890 down.addClassOnClick("x-scroller-btn-click");
45891 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
45893 this.resizeEl = this.el;
45894 this.el = wrap; this.up = up; this.down = down;
45897 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
45899 wheelIncrement : 5,
45900 scrollUp : function(){
45901 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
45904 scrollDown : function(){
45905 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
45908 afterScroll : function(){
45909 var el = this.resizeEl;
45910 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
45911 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45912 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45915 setSize : function(){
45916 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
45917 this.afterScroll();
45920 onWheel : function(e){
45921 var d = e.getWheelDelta();
45922 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
45923 this.afterScroll();
45927 setContent : function(content, loadScripts){
45928 this.resizeEl.update(content, loadScripts);
45942 * @class Roo.TreePanel
45943 * @extends Roo.ContentPanel
45945 * Create a new TreePanel. - defaults to fit/scoll contents.
45946 * @param {String/Object} config A string to set only the panel's title, or a config object
45947 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
45949 Roo.TreePanel = function(config){
45950 var el = config.el;
45951 var tree = config.tree;
45952 delete config.tree;
45953 delete config.el; // hopefull!
45955 // wrapper for IE7 strict & safari scroll issue
45957 var treeEl = el.createChild();
45958 config.resizeEl = treeEl;
45962 Roo.TreePanel.superclass.constructor.call(this, el, config);
45965 this.tree = new Roo.tree.TreePanel(treeEl , tree);
45966 //console.log(tree);
45967 this.on('activate', function()
45969 if (this.tree.rendered) {
45972 //console.log('render tree');
45973 this.tree.render();
45976 this.on('resize', function (cp, w, h) {
45977 this.tree.innerCt.setWidth(w);
45978 this.tree.innerCt.setHeight(h);
45979 this.tree.innerCt.setStyle('overflow-y', 'auto');
45986 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
46003 * Ext JS Library 1.1.1
46004 * Copyright(c) 2006-2007, Ext JS, LLC.
46006 * Originally Released Under LGPL - original licence link has changed is not relivant.
46009 * <script type="text/javascript">
46014 * @class Roo.ReaderLayout
46015 * @extends Roo.BorderLayout
46016 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46017 * center region containing two nested regions (a top one for a list view and one for item preview below),
46018 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46019 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46020 * expedites the setup of the overall layout and regions for this common application style.
46023 var reader = new Roo.ReaderLayout();
46024 var CP = Roo.ContentPanel; // shortcut for adding
46026 reader.beginUpdate();
46027 reader.add("north", new CP("north", "North"));
46028 reader.add("west", new CP("west", {title: "West"}));
46029 reader.add("east", new CP("east", {title: "East"}));
46031 reader.regions.listView.add(new CP("listView", "List"));
46032 reader.regions.preview.add(new CP("preview", "Preview"));
46033 reader.endUpdate();
46036 * Create a new ReaderLayout
46037 * @param {Object} config Configuration options
46038 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46039 * document.body if omitted)
46041 Roo.ReaderLayout = function(config, renderTo){
46042 var c = config || {size:{}};
46043 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46044 north: c.north !== false ? Roo.apply({
46048 }, c.north) : false,
46049 west: c.west !== false ? Roo.apply({
46057 margins:{left:5,right:0,bottom:5,top:5},
46058 cmargins:{left:5,right:5,bottom:5,top:5}
46059 }, c.west) : false,
46060 east: c.east !== false ? Roo.apply({
46068 margins:{left:0,right:5,bottom:5,top:5},
46069 cmargins:{left:5,right:5,bottom:5,top:5}
46070 }, c.east) : false,
46071 center: Roo.apply({
46072 tabPosition: 'top',
46076 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46080 this.el.addClass('x-reader');
46082 this.beginUpdate();
46084 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46085 south: c.preview !== false ? Roo.apply({
46092 cmargins:{top:5,left:0, right:0, bottom:0}
46093 }, c.preview) : false,
46094 center: Roo.apply({
46100 this.add('center', new Roo.NestedLayoutPanel(inner,
46101 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46105 this.regions.preview = inner.getRegion('south');
46106 this.regions.listView = inner.getRegion('center');
46109 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46111 * Ext JS Library 1.1.1
46112 * Copyright(c) 2006-2007, Ext JS, LLC.
46114 * Originally Released Under LGPL - original licence link has changed is not relivant.
46117 * <script type="text/javascript">
46121 * @class Roo.grid.Grid
46122 * @extends Roo.util.Observable
46123 * This class represents the primary interface of a component based grid control.
46124 * <br><br>Usage:<pre><code>
46125 var grid = new Roo.grid.Grid("my-container-id", {
46128 selModel: mySelectionModel,
46129 autoSizeColumns: true,
46130 monitorWindowResize: false,
46131 trackMouseOver: true
46136 * <b>Common Problems:</b><br/>
46137 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46138 * element will correct this<br/>
46139 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46140 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46141 * are unpredictable.<br/>
46142 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46143 * grid to calculate dimensions/offsets.<br/>
46145 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46146 * The container MUST have some type of size defined for the grid to fill. The container will be
46147 * automatically set to position relative if it isn't already.
46148 * @param {Object} config A config object that sets properties on this grid.
46150 Roo.grid.Grid = function(container, config){
46151 // initialize the container
46152 this.container = Roo.get(container);
46153 this.container.update("");
46154 this.container.setStyle("overflow", "hidden");
46155 this.container.addClass('x-grid-container');
46157 this.id = this.container.id;
46159 Roo.apply(this, config);
46160 // check and correct shorthanded configs
46162 this.dataSource = this.ds;
46166 this.colModel = this.cm;
46170 this.selModel = this.sm;
46174 if (this.selModel) {
46175 this.selModel = Roo.factory(this.selModel, Roo.grid);
46176 this.sm = this.selModel;
46177 this.sm.xmodule = this.xmodule || false;
46179 if (typeof(this.colModel.config) == 'undefined') {
46180 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46181 this.cm = this.colModel;
46182 this.cm.xmodule = this.xmodule || false;
46184 if (this.dataSource) {
46185 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46186 this.ds = this.dataSource;
46187 this.ds.xmodule = this.xmodule || false;
46194 this.container.setWidth(this.width);
46198 this.container.setHeight(this.height);
46205 * The raw click event for the entire grid.
46206 * @param {Roo.EventObject} e
46211 * The raw dblclick event for the entire grid.
46212 * @param {Roo.EventObject} e
46216 * @event contextmenu
46217 * The raw contextmenu event for the entire grid.
46218 * @param {Roo.EventObject} e
46220 "contextmenu" : true,
46223 * The raw mousedown event for the entire grid.
46224 * @param {Roo.EventObject} e
46226 "mousedown" : true,
46229 * The raw mouseup event for the entire grid.
46230 * @param {Roo.EventObject} e
46235 * The raw mouseover event for the entire grid.
46236 * @param {Roo.EventObject} e
46238 "mouseover" : true,
46241 * The raw mouseout event for the entire grid.
46242 * @param {Roo.EventObject} e
46247 * The raw keypress event for the entire grid.
46248 * @param {Roo.EventObject} e
46253 * The raw keydown event for the entire grid.
46254 * @param {Roo.EventObject} e
46262 * Fires when a cell is clicked
46263 * @param {Grid} this
46264 * @param {Number} rowIndex
46265 * @param {Number} columnIndex
46266 * @param {Roo.EventObject} e
46268 "cellclick" : true,
46270 * @event celldblclick
46271 * Fires when a cell is double clicked
46272 * @param {Grid} this
46273 * @param {Number} rowIndex
46274 * @param {Number} columnIndex
46275 * @param {Roo.EventObject} e
46277 "celldblclick" : true,
46280 * Fires when a row is clicked
46281 * @param {Grid} this
46282 * @param {Number} rowIndex
46283 * @param {Roo.EventObject} e
46287 * @event rowdblclick
46288 * Fires when a row is double clicked
46289 * @param {Grid} this
46290 * @param {Number} rowIndex
46291 * @param {Roo.EventObject} e
46293 "rowdblclick" : true,
46295 * @event headerclick
46296 * Fires when a header is clicked
46297 * @param {Grid} this
46298 * @param {Number} columnIndex
46299 * @param {Roo.EventObject} e
46301 "headerclick" : true,
46303 * @event headerdblclick
46304 * Fires when a header cell is double clicked
46305 * @param {Grid} this
46306 * @param {Number} columnIndex
46307 * @param {Roo.EventObject} e
46309 "headerdblclick" : true,
46311 * @event rowcontextmenu
46312 * Fires when a row is right clicked
46313 * @param {Grid} this
46314 * @param {Number} rowIndex
46315 * @param {Roo.EventObject} e
46317 "rowcontextmenu" : true,
46319 * @event cellcontextmenu
46320 * Fires when a cell is right clicked
46321 * @param {Grid} this
46322 * @param {Number} rowIndex
46323 * @param {Number} cellIndex
46324 * @param {Roo.EventObject} e
46326 "cellcontextmenu" : true,
46328 * @event headercontextmenu
46329 * Fires when a header is right clicked
46330 * @param {Grid} this
46331 * @param {Number} columnIndex
46332 * @param {Roo.EventObject} e
46334 "headercontextmenu" : true,
46336 * @event bodyscroll
46337 * Fires when the body element is scrolled
46338 * @param {Number} scrollLeft
46339 * @param {Number} scrollTop
46341 "bodyscroll" : true,
46343 * @event columnresize
46344 * Fires when the user resizes a column
46345 * @param {Number} columnIndex
46346 * @param {Number} newSize
46348 "columnresize" : true,
46350 * @event columnmove
46351 * Fires when the user moves a column
46352 * @param {Number} oldIndex
46353 * @param {Number} newIndex
46355 "columnmove" : true,
46358 * Fires when row(s) start being dragged
46359 * @param {Grid} this
46360 * @param {Roo.GridDD} dd The drag drop object
46361 * @param {event} e The raw browser event
46363 "startdrag" : true,
46366 * Fires when a drag operation is complete
46367 * @param {Grid} this
46368 * @param {Roo.GridDD} dd The drag drop object
46369 * @param {event} e The raw browser event
46374 * Fires when dragged row(s) are dropped on a valid DD target
46375 * @param {Grid} this
46376 * @param {Roo.GridDD} dd The drag drop object
46377 * @param {String} targetId The target drag drop object
46378 * @param {event} e The raw browser event
46383 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46384 * @param {Grid} this
46385 * @param {Roo.GridDD} dd The drag drop object
46386 * @param {String} targetId The target drag drop object
46387 * @param {event} e The raw browser event
46392 * Fires when the dragged row(s) first cross another DD target while being dragged
46393 * @param {Grid} this
46394 * @param {Roo.GridDD} dd The drag drop object
46395 * @param {String} targetId The target drag drop object
46396 * @param {event} e The raw browser event
46398 "dragenter" : true,
46401 * Fires when the dragged row(s) leave another DD target while being dragged
46402 * @param {Grid} this
46403 * @param {Roo.GridDD} dd The drag drop object
46404 * @param {String} targetId The target drag drop object
46405 * @param {event} e The raw browser event
46410 * Fires when the grid is rendered
46411 * @param {Grid} grid
46416 Roo.grid.Grid.superclass.constructor.call(this);
46418 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46421 * @cfg {String} ddGroup - drag drop group.
46425 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46427 minColumnWidth : 25,
46430 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46431 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46432 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46434 autoSizeColumns : false,
46437 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46439 autoSizeHeaders : true,
46442 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46444 monitorWindowResize : true,
46447 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46448 * rows measured to get a columns size. Default is 0 (all rows).
46450 maxRowsToMeasure : 0,
46453 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46455 trackMouseOver : true,
46458 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46462 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46464 enableDragDrop : false,
46467 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46469 enableColumnMove : true,
46472 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46474 enableColumnHide : true,
46477 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46479 enableRowHeightSync : false,
46482 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46487 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46489 autoHeight : false,
46492 * @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.
46494 autoExpandColumn : false,
46497 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46500 autoExpandMin : 50,
46503 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46505 autoExpandMax : 1000,
46508 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46513 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46517 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46524 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46525 * of a fixed width. Default is false.
46528 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46531 * Called once after all setup has been completed and the grid is ready to be rendered.
46532 * @return {Roo.grid.Grid} this
46534 render : function(){
46535 var c = this.container;
46536 // try to detect autoHeight/width mode
46537 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46538 this.autoHeight = true;
46540 var view = this.getView();
46543 c.on("click", this.onClick, this);
46544 c.on("dblclick", this.onDblClick, this);
46545 c.on("contextmenu", this.onContextMenu, this);
46546 c.on("keydown", this.onKeyDown, this);
46548 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46550 this.getSelectionModel().init(this);
46555 this.loadMask = new Roo.LoadMask(this.container,
46556 Roo.apply({store:this.dataSource}, this.loadMask));
46560 if (this.toolbar && this.toolbar.xtype) {
46561 this.toolbar.container = this.getView().getHeaderPanel(true);
46562 this.toolbar = new Ext.Toolbar(this.toolbar);
46564 if (this.footer && this.footer.xtype) {
46565 this.footer.dataSource = this.getDataSource();
46566 this.footer.container = this.getView().getFooterPanel(true);
46567 this.footer = Roo.factory(this.footer, Roo);
46569 if (this.dropTarget && this.dropTarget.xtype) {
46570 delete this.dropTarget.xtype;
46571 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46575 this.rendered = true;
46576 this.fireEvent('render', this);
46581 * Reconfigures the grid to use a different Store and Column Model.
46582 * The View will be bound to the new objects and refreshed.
46583 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46584 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46586 reconfigure : function(dataSource, colModel){
46588 this.loadMask.destroy();
46589 this.loadMask = new Roo.LoadMask(this.container,
46590 Roo.apply({store:dataSource}, this.loadMask));
46592 this.view.bind(dataSource, colModel);
46593 this.dataSource = dataSource;
46594 this.colModel = colModel;
46595 this.view.refresh(true);
46599 onKeyDown : function(e){
46600 this.fireEvent("keydown", e);
46604 * Destroy this grid.
46605 * @param {Boolean} removeEl True to remove the element
46607 destroy : function(removeEl, keepListeners){
46609 this.loadMask.destroy();
46611 var c = this.container;
46612 c.removeAllListeners();
46613 this.view.destroy();
46614 this.colModel.purgeListeners();
46615 if(!keepListeners){
46616 this.purgeListeners();
46619 if(removeEl === true){
46625 processEvent : function(name, e){
46626 this.fireEvent(name, e);
46627 var t = e.getTarget();
46629 var header = v.findHeaderIndex(t);
46630 if(header !== false){
46631 this.fireEvent("header" + name, this, header, e);
46633 var row = v.findRowIndex(t);
46634 var cell = v.findCellIndex(t);
46636 this.fireEvent("row" + name, this, row, e);
46637 if(cell !== false){
46638 this.fireEvent("cell" + name, this, row, cell, e);
46645 onClick : function(e){
46646 this.processEvent("click", e);
46650 onContextMenu : function(e, t){
46651 this.processEvent("contextmenu", e);
46655 onDblClick : function(e){
46656 this.processEvent("dblclick", e);
46660 walkCells : function(row, col, step, fn, scope){
46661 var cm = this.colModel, clen = cm.getColumnCount();
46662 var ds = this.dataSource, rlen = ds.getCount(), first = true;
46674 if(fn.call(scope || this, row, col, cm) === true){
46692 if(fn.call(scope || this, row, col, cm) === true){
46704 getSelections : function(){
46705 return this.selModel.getSelections();
46709 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
46710 * but if manual update is required this method will initiate it.
46712 autoSize : function(){
46714 this.view.layout();
46715 if(this.view.adjustForScroll){
46716 this.view.adjustForScroll();
46722 * Returns the grid's underlying element.
46723 * @return {Element} The element
46725 getGridEl : function(){
46726 return this.container;
46729 // private for compatibility, overridden by editor grid
46730 stopEditing : function(){},
46733 * Returns the grid's SelectionModel.
46734 * @return {SelectionModel}
46736 getSelectionModel : function(){
46737 if(!this.selModel){
46738 this.selModel = new Roo.grid.RowSelectionModel();
46740 return this.selModel;
46744 * Returns the grid's DataSource.
46745 * @return {DataSource}
46747 getDataSource : function(){
46748 return this.dataSource;
46752 * Returns the grid's ColumnModel.
46753 * @return {ColumnModel}
46755 getColumnModel : function(){
46756 return this.colModel;
46760 * Returns the grid's GridView object.
46761 * @return {GridView}
46763 getView : function(){
46765 this.view = new Roo.grid.GridView(this.viewConfig);
46770 * Called to get grid's drag proxy text, by default returns this.ddText.
46773 getDragDropText : function(){
46774 var count = this.selModel.getCount();
46775 return String.format(this.ddText, count, count == 1 ? '' : 's');
46779 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
46780 * %0 is replaced with the number of selected rows.
46783 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
46785 * Ext JS Library 1.1.1
46786 * Copyright(c) 2006-2007, Ext JS, LLC.
46788 * Originally Released Under LGPL - original licence link has changed is not relivant.
46791 * <script type="text/javascript">
46794 Roo.grid.AbstractGridView = function(){
46798 "beforerowremoved" : true,
46799 "beforerowsinserted" : true,
46800 "beforerefresh" : true,
46801 "rowremoved" : true,
46802 "rowsinserted" : true,
46803 "rowupdated" : true,
46806 Roo.grid.AbstractGridView.superclass.constructor.call(this);
46809 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
46810 rowClass : "x-grid-row",
46811 cellClass : "x-grid-cell",
46812 tdClass : "x-grid-td",
46813 hdClass : "x-grid-hd",
46814 splitClass : "x-grid-hd-split",
46816 init: function(grid){
46818 var cid = this.grid.getGridEl().id;
46819 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
46820 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
46821 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
46822 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
46825 getColumnRenderers : function(){
46826 var renderers = [];
46827 var cm = this.grid.colModel;
46828 var colCount = cm.getColumnCount();
46829 for(var i = 0; i < colCount; i++){
46830 renderers[i] = cm.getRenderer(i);
46835 getColumnIds : function(){
46837 var cm = this.grid.colModel;
46838 var colCount = cm.getColumnCount();
46839 for(var i = 0; i < colCount; i++){
46840 ids[i] = cm.getColumnId(i);
46845 getDataIndexes : function(){
46846 if(!this.indexMap){
46847 this.indexMap = this.buildIndexMap();
46849 return this.indexMap.colToData;
46852 getColumnIndexByDataIndex : function(dataIndex){
46853 if(!this.indexMap){
46854 this.indexMap = this.buildIndexMap();
46856 return this.indexMap.dataToCol[dataIndex];
46860 * Set a css style for a column dynamically.
46861 * @param {Number} colIndex The index of the column
46862 * @param {String} name The css property name
46863 * @param {String} value The css value
46865 setCSSStyle : function(colIndex, name, value){
46866 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
46867 Roo.util.CSS.updateRule(selector, name, value);
46870 generateRules : function(cm){
46871 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
46872 Roo.util.CSS.removeStyleSheet(rulesId);
46873 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46874 var cid = cm.getColumnId(i);
46875 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
46876 this.tdSelector, cid, " {\n}\n",
46877 this.hdSelector, cid, " {\n}\n",
46878 this.splitSelector, cid, " {\n}\n");
46880 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46884 * Ext JS Library 1.1.1
46885 * Copyright(c) 2006-2007, Ext JS, LLC.
46887 * Originally Released Under LGPL - original licence link has changed is not relivant.
46890 * <script type="text/javascript">
46894 // This is a support class used internally by the Grid components
46895 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
46897 this.view = grid.getView();
46898 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46899 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
46901 this.setHandleElId(Roo.id(hd));
46902 this.setOuterHandleElId(Roo.id(hd2));
46904 this.scroll = false;
46906 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
46908 getDragData : function(e){
46909 var t = Roo.lib.Event.getTarget(e);
46910 var h = this.view.findHeaderCell(t);
46912 return {ddel: h.firstChild, header:h};
46917 onInitDrag : function(e){
46918 this.view.headersDisabled = true;
46919 var clone = this.dragData.ddel.cloneNode(true);
46920 clone.id = Roo.id();
46921 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
46922 this.proxy.update(clone);
46926 afterValidDrop : function(){
46928 setTimeout(function(){
46929 v.headersDisabled = false;
46933 afterInvalidDrop : function(){
46935 setTimeout(function(){
46936 v.headersDisabled = false;
46942 * Ext JS Library 1.1.1
46943 * Copyright(c) 2006-2007, Ext JS, LLC.
46945 * Originally Released Under LGPL - original licence link has changed is not relivant.
46948 * <script type="text/javascript">
46951 // This is a support class used internally by the Grid components
46952 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
46954 this.view = grid.getView();
46955 // split the proxies so they don't interfere with mouse events
46956 this.proxyTop = Roo.DomHelper.append(document.body, {
46957 cls:"col-move-top", html:" "
46959 this.proxyBottom = Roo.DomHelper.append(document.body, {
46960 cls:"col-move-bottom", html:" "
46962 this.proxyTop.hide = this.proxyBottom.hide = function(){
46963 this.setLeftTop(-100,-100);
46964 this.setStyle("visibility", "hidden");
46966 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46967 // temporarily disabled
46968 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
46969 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
46971 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
46972 proxyOffsets : [-4, -9],
46973 fly: Roo.Element.fly,
46975 getTargetFromEvent : function(e){
46976 var t = Roo.lib.Event.getTarget(e);
46977 var cindex = this.view.findCellIndex(t);
46978 if(cindex !== false){
46979 return this.view.getHeaderCell(cindex);
46983 nextVisible : function(h){
46984 var v = this.view, cm = this.grid.colModel;
46987 if(!cm.isHidden(v.getCellIndex(h))){
46995 prevVisible : function(h){
46996 var v = this.view, cm = this.grid.colModel;
46999 if(!cm.isHidden(v.getCellIndex(h))){
47007 positionIndicator : function(h, n, e){
47008 var x = Roo.lib.Event.getPageX(e);
47009 var r = Roo.lib.Dom.getRegion(n.firstChild);
47010 var px, pt, py = r.top + this.proxyOffsets[1];
47011 if((r.right - x) <= (r.right-r.left)/2){
47012 px = r.right+this.view.borderWidth;
47018 var oldIndex = this.view.getCellIndex(h);
47019 var newIndex = this.view.getCellIndex(n);
47021 if(this.grid.colModel.isFixed(newIndex)){
47025 var locked = this.grid.colModel.isLocked(newIndex);
47030 if(oldIndex < newIndex){
47033 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47036 px += this.proxyOffsets[0];
47037 this.proxyTop.setLeftTop(px, py);
47038 this.proxyTop.show();
47039 if(!this.bottomOffset){
47040 this.bottomOffset = this.view.mainHd.getHeight();
47042 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47043 this.proxyBottom.show();
47047 onNodeEnter : function(n, dd, e, data){
47048 if(data.header != n){
47049 this.positionIndicator(data.header, n, e);
47053 onNodeOver : function(n, dd, e, data){
47054 var result = false;
47055 if(data.header != n){
47056 result = this.positionIndicator(data.header, n, e);
47059 this.proxyTop.hide();
47060 this.proxyBottom.hide();
47062 return result ? this.dropAllowed : this.dropNotAllowed;
47065 onNodeOut : function(n, dd, e, data){
47066 this.proxyTop.hide();
47067 this.proxyBottom.hide();
47070 onNodeDrop : function(n, dd, e, data){
47071 var h = data.header;
47073 var cm = this.grid.colModel;
47074 var x = Roo.lib.Event.getPageX(e);
47075 var r = Roo.lib.Dom.getRegion(n.firstChild);
47076 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47077 var oldIndex = this.view.getCellIndex(h);
47078 var newIndex = this.view.getCellIndex(n);
47079 var locked = cm.isLocked(newIndex);
47083 if(oldIndex < newIndex){
47086 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47089 cm.setLocked(oldIndex, locked, true);
47090 cm.moveColumn(oldIndex, newIndex);
47091 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47099 * Ext JS Library 1.1.1
47100 * Copyright(c) 2006-2007, Ext JS, LLC.
47102 * Originally Released Under LGPL - original licence link has changed is not relivant.
47105 * <script type="text/javascript">
47109 * @class Roo.grid.GridView
47110 * @extends Roo.util.Observable
47113 * @param {Object} config
47115 Roo.grid.GridView = function(config){
47116 Roo.grid.GridView.superclass.constructor.call(this);
47119 Roo.apply(this, config);
47122 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47125 * Override this function to apply custom css classes to rows during rendering
47126 * @param {Record} record The record
47127 * @param {Number} index
47128 * @method getRowClass
47130 rowClass : "x-grid-row",
47132 cellClass : "x-grid-col",
47134 tdClass : "x-grid-td",
47136 hdClass : "x-grid-hd",
47138 splitClass : "x-grid-split",
47140 sortClasses : ["sort-asc", "sort-desc"],
47142 enableMoveAnim : false,
47146 dh : Roo.DomHelper,
47148 fly : Roo.Element.fly,
47150 css : Roo.util.CSS,
47156 scrollIncrement : 22,
47158 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47160 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47162 bind : function(ds, cm){
47164 this.ds.un("load", this.onLoad, this);
47165 this.ds.un("datachanged", this.onDataChange, this);
47166 this.ds.un("add", this.onAdd, this);
47167 this.ds.un("remove", this.onRemove, this);
47168 this.ds.un("update", this.onUpdate, this);
47169 this.ds.un("clear", this.onClear, this);
47172 ds.on("load", this.onLoad, this);
47173 ds.on("datachanged", this.onDataChange, this);
47174 ds.on("add", this.onAdd, this);
47175 ds.on("remove", this.onRemove, this);
47176 ds.on("update", this.onUpdate, this);
47177 ds.on("clear", this.onClear, this);
47182 this.cm.un("widthchange", this.onColWidthChange, this);
47183 this.cm.un("headerchange", this.onHeaderChange, this);
47184 this.cm.un("hiddenchange", this.onHiddenChange, this);
47185 this.cm.un("columnmoved", this.onColumnMove, this);
47186 this.cm.un("columnlockchange", this.onColumnLock, this);
47189 this.generateRules(cm);
47190 cm.on("widthchange", this.onColWidthChange, this);
47191 cm.on("headerchange", this.onHeaderChange, this);
47192 cm.on("hiddenchange", this.onHiddenChange, this);
47193 cm.on("columnmoved", this.onColumnMove, this);
47194 cm.on("columnlockchange", this.onColumnLock, this);
47199 init: function(grid){
47200 Roo.grid.GridView.superclass.init.call(this, grid);
47202 this.bind(grid.dataSource, grid.colModel);
47204 grid.on("headerclick", this.handleHeaderClick, this);
47206 if(grid.trackMouseOver){
47207 grid.on("mouseover", this.onRowOver, this);
47208 grid.on("mouseout", this.onRowOut, this);
47210 grid.cancelTextSelection = function(){};
47211 this.gridId = grid.id;
47213 var tpls = this.templates || {};
47216 tpls.master = new Roo.Template(
47217 '<div class="x-grid" hidefocus="true">',
47218 '<div class="x-grid-topbar"></div>',
47219 '<div class="x-grid-scroller"><div></div></div>',
47220 '<div class="x-grid-locked">',
47221 '<div class="x-grid-header">{lockedHeader}</div>',
47222 '<div class="x-grid-body">{lockedBody}</div>',
47224 '<div class="x-grid-viewport">',
47225 '<div class="x-grid-header">{header}</div>',
47226 '<div class="x-grid-body">{body}</div>',
47228 '<div class="x-grid-bottombar"></div>',
47229 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47230 '<div class="x-grid-resize-proxy"> </div>',
47233 tpls.master.disableformats = true;
47237 tpls.header = new Roo.Template(
47238 '<table border="0" cellspacing="0" cellpadding="0">',
47239 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47242 tpls.header.disableformats = true;
47244 tpls.header.compile();
47247 tpls.hcell = new Roo.Template(
47248 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47249 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47252 tpls.hcell.disableFormats = true;
47254 tpls.hcell.compile();
47257 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47258 tpls.hsplit.disableFormats = true;
47260 tpls.hsplit.compile();
47263 tpls.body = new Roo.Template(
47264 '<table border="0" cellspacing="0" cellpadding="0">',
47265 "<tbody>{rows}</tbody>",
47268 tpls.body.disableFormats = true;
47270 tpls.body.compile();
47273 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47274 tpls.row.disableFormats = true;
47276 tpls.row.compile();
47279 tpls.cell = new Roo.Template(
47280 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47281 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47284 tpls.cell.disableFormats = true;
47286 tpls.cell.compile();
47288 this.templates = tpls;
47291 // remap these for backwards compat
47292 onColWidthChange : function(){
47293 this.updateColumns.apply(this, arguments);
47295 onHeaderChange : function(){
47296 this.updateHeaders.apply(this, arguments);
47298 onHiddenChange : function(){
47299 this.handleHiddenChange.apply(this, arguments);
47301 onColumnMove : function(){
47302 this.handleColumnMove.apply(this, arguments);
47304 onColumnLock : function(){
47305 this.handleLockChange.apply(this, arguments);
47308 onDataChange : function(){
47310 this.updateHeaderSortState();
47313 onClear : function(){
47317 onUpdate : function(ds, record){
47318 this.refreshRow(record);
47321 refreshRow : function(record){
47322 var ds = this.ds, index;
47323 if(typeof record == 'number'){
47325 record = ds.getAt(index);
47327 index = ds.indexOf(record);
47329 this.insertRows(ds, index, index, true);
47330 this.onRemove(ds, record, index+1, true);
47331 this.syncRowHeights(index, index);
47333 this.fireEvent("rowupdated", this, index, record);
47336 onAdd : function(ds, records, index){
47337 this.insertRows(ds, index, index + (records.length-1));
47340 onRemove : function(ds, record, index, isUpdate){
47341 if(isUpdate !== true){
47342 this.fireEvent("beforerowremoved", this, index, record);
47344 var bt = this.getBodyTable(), lt = this.getLockedTable();
47345 if(bt.rows[index]){
47346 bt.firstChild.removeChild(bt.rows[index]);
47348 if(lt.rows[index]){
47349 lt.firstChild.removeChild(lt.rows[index]);
47351 if(isUpdate !== true){
47352 this.stripeRows(index);
47353 this.syncRowHeights(index, index);
47355 this.fireEvent("rowremoved", this, index, record);
47359 onLoad : function(){
47360 this.scrollToTop();
47364 * Scrolls the grid to the top
47366 scrollToTop : function(){
47368 this.scroller.dom.scrollTop = 0;
47374 * Gets a panel in the header of the grid that can be used for toolbars etc.
47375 * After modifying the contents of this panel a call to grid.autoSize() may be
47376 * required to register any changes in size.
47377 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47378 * @return Roo.Element
47380 getHeaderPanel : function(doShow){
47382 this.headerPanel.show();
47384 return this.headerPanel;
47388 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47389 * After modifying the contents of this panel a call to grid.autoSize() may be
47390 * required to register any changes in size.
47391 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47392 * @return Roo.Element
47394 getFooterPanel : function(doShow){
47396 this.footerPanel.show();
47398 return this.footerPanel;
47401 initElements : function(){
47402 var E = Roo.Element;
47403 var el = this.grid.getGridEl().dom.firstChild;
47404 var cs = el.childNodes;
47406 this.el = new E(el);
47407 this.headerPanel = new E(el.firstChild);
47408 this.headerPanel.enableDisplayMode("block");
47410 this.scroller = new E(cs[1]);
47411 this.scrollSizer = new E(this.scroller.dom.firstChild);
47413 this.lockedWrap = new E(cs[2]);
47414 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47415 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47417 this.mainWrap = new E(cs[3]);
47418 this.mainHd = new E(this.mainWrap.dom.firstChild);
47419 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47421 this.footerPanel = new E(cs[4]);
47422 this.footerPanel.enableDisplayMode("block");
47424 this.focusEl = new E(cs[5]);
47425 this.focusEl.swallowEvent("click", true);
47426 this.resizeProxy = new E(cs[6]);
47428 this.headerSelector = String.format(
47429 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47430 this.lockedHd.id, this.mainHd.id
47433 this.splitterSelector = String.format(
47434 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47435 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47438 idToCssName : function(s)
47440 return s.replace(/[^a-z0-9]+/ig, '-');
47443 getHeaderCell : function(index){
47444 return Roo.DomQuery.select(this.headerSelector)[index];
47447 getHeaderCellMeasure : function(index){
47448 return this.getHeaderCell(index).firstChild;
47451 getHeaderCellText : function(index){
47452 return this.getHeaderCell(index).firstChild.firstChild;
47455 getLockedTable : function(){
47456 return this.lockedBody.dom.firstChild;
47459 getBodyTable : function(){
47460 return this.mainBody.dom.firstChild;
47463 getLockedRow : function(index){
47464 return this.getLockedTable().rows[index];
47467 getRow : function(index){
47468 return this.getBodyTable().rows[index];
47471 getRowComposite : function(index){
47473 this.rowEl = new Roo.CompositeElementLite();
47475 var els = [], lrow, mrow;
47476 if(lrow = this.getLockedRow(index)){
47479 if(mrow = this.getRow(index)){
47482 this.rowEl.elements = els;
47486 getCell : function(rowIndex, colIndex){
47487 var locked = this.cm.getLockedCount();
47489 if(colIndex < locked){
47490 source = this.lockedBody.dom.firstChild;
47492 source = this.mainBody.dom.firstChild;
47493 colIndex -= locked;
47495 return source.rows[rowIndex].childNodes[colIndex];
47498 getCellText : function(rowIndex, colIndex){
47499 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47502 getCellBox : function(cell){
47503 var b = this.fly(cell).getBox();
47504 if(Roo.isOpera){ // opera fails to report the Y
47505 b.y = cell.offsetTop + this.mainBody.getY();
47510 getCellIndex : function(cell){
47511 var id = String(cell.className).match(this.cellRE);
47513 return parseInt(id[1], 10);
47518 findHeaderIndex : function(n){
47519 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47520 return r ? this.getCellIndex(r) : false;
47523 findHeaderCell : function(n){
47524 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47525 return r ? r : false;
47528 findRowIndex : function(n){
47532 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47533 return r ? r.rowIndex : false;
47536 findCellIndex : function(node){
47537 var stop = this.el.dom;
47538 while(node && node != stop){
47539 if(this.findRE.test(node.className)){
47540 return this.getCellIndex(node);
47542 node = node.parentNode;
47547 getColumnId : function(index){
47548 return this.cm.getColumnId(index);
47551 getSplitters : function(){
47552 if(this.splitterSelector){
47553 return Roo.DomQuery.select(this.splitterSelector);
47559 getSplitter : function(index){
47560 return this.getSplitters()[index];
47563 onRowOver : function(e, t){
47565 if((row = this.findRowIndex(t)) !== false){
47566 this.getRowComposite(row).addClass("x-grid-row-over");
47570 onRowOut : function(e, t){
47572 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47573 this.getRowComposite(row).removeClass("x-grid-row-over");
47577 renderHeaders : function(){
47579 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47580 var cb = [], lb = [], sb = [], lsb = [], p = {};
47581 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47582 p.cellId = "x-grid-hd-0-" + i;
47583 p.splitId = "x-grid-csplit-0-" + i;
47584 p.id = cm.getColumnId(i);
47585 p.title = cm.getColumnTooltip(i) || "";
47586 p.value = cm.getColumnHeader(i) || "";
47587 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47588 if(!cm.isLocked(i)){
47589 cb[cb.length] = ct.apply(p);
47590 sb[sb.length] = st.apply(p);
47592 lb[lb.length] = ct.apply(p);
47593 lsb[lsb.length] = st.apply(p);
47596 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47597 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47600 updateHeaders : function(){
47601 var html = this.renderHeaders();
47602 this.lockedHd.update(html[0]);
47603 this.mainHd.update(html[1]);
47607 * Focuses the specified row.
47608 * @param {Number} row The row index
47610 focusRow : function(row){
47611 var x = this.scroller.dom.scrollLeft;
47612 this.focusCell(row, 0, false);
47613 this.scroller.dom.scrollLeft = x;
47617 * Focuses the specified cell.
47618 * @param {Number} row The row index
47619 * @param {Number} col The column index
47620 * @param {Boolean} hscroll false to disable horizontal scrolling
47622 focusCell : function(row, col, hscroll){
47623 var el = this.ensureVisible(row, col, hscroll);
47624 this.focusEl.alignTo(el, "tl-tl");
47626 this.focusEl.focus();
47628 this.focusEl.focus.defer(1, this.focusEl);
47633 * Scrolls the specified cell into view
47634 * @param {Number} row The row index
47635 * @param {Number} col The column index
47636 * @param {Boolean} hscroll false to disable horizontal scrolling
47638 ensureVisible : function(row, col, hscroll){
47639 if(typeof row != "number"){
47640 row = row.rowIndex;
47642 if(row < 0 && row >= this.ds.getCount()){
47645 col = (col !== undefined ? col : 0);
47646 var cm = this.grid.colModel;
47647 while(cm.isHidden(col)){
47651 var el = this.getCell(row, col);
47655 var c = this.scroller.dom;
47657 var ctop = parseInt(el.offsetTop, 10);
47658 var cleft = parseInt(el.offsetLeft, 10);
47659 var cbot = ctop + el.offsetHeight;
47660 var cright = cleft + el.offsetWidth;
47662 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47663 var stop = parseInt(c.scrollTop, 10);
47664 var sleft = parseInt(c.scrollLeft, 10);
47665 var sbot = stop + ch;
47666 var sright = sleft + c.clientWidth;
47669 c.scrollTop = ctop;
47670 }else if(cbot > sbot){
47671 c.scrollTop = cbot-ch;
47674 if(hscroll !== false){
47676 c.scrollLeft = cleft;
47677 }else if(cright > sright){
47678 c.scrollLeft = cright-c.clientWidth;
47684 updateColumns : function(){
47685 this.grid.stopEditing();
47686 var cm = this.grid.colModel, colIds = this.getColumnIds();
47687 //var totalWidth = cm.getTotalWidth();
47689 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47690 //if(cm.isHidden(i)) continue;
47691 var w = cm.getColumnWidth(i);
47692 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47693 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47695 this.updateSplitters();
47698 generateRules : function(cm){
47699 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
47700 Roo.util.CSS.removeStyleSheet(rulesId);
47701 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47702 var cid = cm.getColumnId(i);
47704 if(cm.config[i].align){
47705 align = 'text-align:'+cm.config[i].align+';';
47708 if(cm.isHidden(i)){
47709 hidden = 'display:none;';
47711 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
47713 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
47714 this.hdSelector, cid, " {\n", align, width, "}\n",
47715 this.tdSelector, cid, " {\n",hidden,"\n}\n",
47716 this.splitSelector, cid, " {\n", hidden , "\n}\n");
47718 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47721 updateSplitters : function(){
47722 var cm = this.cm, s = this.getSplitters();
47723 if(s){ // splitters not created yet
47724 var pos = 0, locked = true;
47725 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47726 if(cm.isHidden(i)) continue;
47727 var w = cm.getColumnWidth(i);
47728 if(!cm.isLocked(i) && locked){
47733 s[i].style.left = (pos-this.splitOffset) + "px";
47738 handleHiddenChange : function(colModel, colIndex, hidden){
47740 this.hideColumn(colIndex);
47742 this.unhideColumn(colIndex);
47746 hideColumn : function(colIndex){
47747 var cid = this.getColumnId(colIndex);
47748 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
47749 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
47751 this.updateHeaders();
47753 this.updateSplitters();
47757 unhideColumn : function(colIndex){
47758 var cid = this.getColumnId(colIndex);
47759 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
47760 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
47763 this.updateHeaders();
47765 this.updateSplitters();
47769 insertRows : function(dm, firstRow, lastRow, isUpdate){
47770 if(firstRow == 0 && lastRow == dm.getCount()-1){
47774 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
47776 var s = this.getScrollState();
47777 var markup = this.renderRows(firstRow, lastRow);
47778 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
47779 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
47780 this.restoreScroll(s);
47782 this.fireEvent("rowsinserted", this, firstRow, lastRow);
47783 this.syncRowHeights(firstRow, lastRow);
47784 this.stripeRows(firstRow);
47790 bufferRows : function(markup, target, index){
47791 var before = null, trows = target.rows, tbody = target.tBodies[0];
47792 if(index < trows.length){
47793 before = trows[index];
47795 var b = document.createElement("div");
47796 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
47797 var rows = b.firstChild.rows;
47798 for(var i = 0, len = rows.length; i < len; i++){
47800 tbody.insertBefore(rows[0], before);
47802 tbody.appendChild(rows[0]);
47809 deleteRows : function(dm, firstRow, lastRow){
47810 if(dm.getRowCount()<1){
47811 this.fireEvent("beforerefresh", this);
47812 this.mainBody.update("");
47813 this.lockedBody.update("");
47814 this.fireEvent("refresh", this);
47816 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
47817 var bt = this.getBodyTable();
47818 var tbody = bt.firstChild;
47819 var rows = bt.rows;
47820 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
47821 tbody.removeChild(rows[firstRow]);
47823 this.stripeRows(firstRow);
47824 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
47828 updateRows : function(dataSource, firstRow, lastRow){
47829 var s = this.getScrollState();
47831 this.restoreScroll(s);
47834 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
47838 this.updateHeaderSortState();
47841 getScrollState : function(){
47842 var sb = this.scroller.dom;
47843 return {left: sb.scrollLeft, top: sb.scrollTop};
47846 stripeRows : function(startRow){
47847 if(!this.grid.stripeRows || this.ds.getCount() < 1){
47850 startRow = startRow || 0;
47851 var rows = this.getBodyTable().rows;
47852 var lrows = this.getLockedTable().rows;
47853 var cls = ' x-grid-row-alt ';
47854 for(var i = startRow, len = rows.length; i < len; i++){
47855 var row = rows[i], lrow = lrows[i];
47856 var isAlt = ((i+1) % 2 == 0);
47857 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
47858 if(isAlt == hasAlt){
47862 row.className += " x-grid-row-alt";
47864 row.className = row.className.replace("x-grid-row-alt", "");
47867 lrow.className = row.className;
47872 restoreScroll : function(state){
47873 var sb = this.scroller.dom;
47874 sb.scrollLeft = state.left;
47875 sb.scrollTop = state.top;
47879 syncScroll : function(){
47880 var sb = this.scroller.dom;
47881 var sh = this.mainHd.dom;
47882 var bs = this.mainBody.dom;
47883 var lv = this.lockedBody.dom;
47884 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
47885 lv.scrollTop = bs.scrollTop = sb.scrollTop;
47888 handleScroll : function(e){
47890 var sb = this.scroller.dom;
47891 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
47895 handleWheel : function(e){
47896 var d = e.getWheelDelta();
47897 this.scroller.dom.scrollTop -= d*22;
47898 // set this here to prevent jumpy scrolling on large tables
47899 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
47903 renderRows : function(startRow, endRow){
47904 // pull in all the crap needed to render rows
47905 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
47906 var colCount = cm.getColumnCount();
47908 if(ds.getCount() < 1){
47912 // build a map for all the columns
47914 for(var i = 0; i < colCount; i++){
47915 var name = cm.getDataIndex(i);
47917 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
47918 renderer : cm.getRenderer(i),
47919 id : cm.getColumnId(i),
47920 locked : cm.isLocked(i)
47924 startRow = startRow || 0;
47925 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
47927 // records to render
47928 var rs = ds.getRange(startRow, endRow);
47930 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
47933 // As much as I hate to duplicate code, this was branched because FireFox really hates
47934 // [].join("") on strings. The performance difference was substantial enough to
47935 // branch this function
47936 doRender : Roo.isGecko ?
47937 function(cs, rs, ds, startRow, colCount, stripe){
47938 var ts = this.templates, ct = ts.cell, rt = ts.row;
47940 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47941 for(var j = 0, len = rs.length; j < len; j++){
47942 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
47943 for(var i = 0; i < colCount; i++){
47945 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47947 p.css = p.attr = "";
47948 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47949 if(p.value == undefined || p.value === "") p.value = " ";
47950 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47951 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47953 var markup = ct.apply(p);
47961 if(stripe && ((rowIndex+1) % 2 == 0)){
47962 alt[0] = "x-grid-row-alt";
47965 alt[1] = " x-grid-dirty-row";
47968 if(this.getRowClass){
47969 alt[2] = this.getRowClass(r, rowIndex);
47971 rp.alt = alt.join(" ");
47972 lbuf+= rt.apply(rp);
47974 buf+= rt.apply(rp);
47976 return [lbuf, buf];
47978 function(cs, rs, ds, startRow, colCount, stripe){
47979 var ts = this.templates, ct = ts.cell, rt = ts.row;
47981 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47982 for(var j = 0, len = rs.length; j < len; j++){
47983 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
47984 for(var i = 0; i < colCount; i++){
47986 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47988 p.css = p.attr = "";
47989 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47990 if(p.value == undefined || p.value === "") p.value = " ";
47991 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47992 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47994 var markup = ct.apply(p);
47996 cb[cb.length] = markup;
47998 lcb[lcb.length] = markup;
48002 if(stripe && ((rowIndex+1) % 2 == 0)){
48003 alt[0] = "x-grid-row-alt";
48006 alt[1] = " x-grid-dirty-row";
48009 if(this.getRowClass){
48010 alt[2] = this.getRowClass(r, rowIndex);
48012 rp.alt = alt.join(" ");
48013 rp.cells = lcb.join("");
48014 lbuf[lbuf.length] = rt.apply(rp);
48015 rp.cells = cb.join("");
48016 buf[buf.length] = rt.apply(rp);
48018 return [lbuf.join(""), buf.join("")];
48021 renderBody : function(){
48022 var markup = this.renderRows();
48023 var bt = this.templates.body;
48024 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48028 * Refreshes the grid
48029 * @param {Boolean} headersToo
48031 refresh : function(headersToo){
48032 this.fireEvent("beforerefresh", this);
48033 this.grid.stopEditing();
48034 var result = this.renderBody();
48035 this.lockedBody.update(result[0]);
48036 this.mainBody.update(result[1]);
48037 if(headersToo === true){
48038 this.updateHeaders();
48039 this.updateColumns();
48040 this.updateSplitters();
48041 this.updateHeaderSortState();
48043 this.syncRowHeights();
48045 this.fireEvent("refresh", this);
48048 handleColumnMove : function(cm, oldIndex, newIndex){
48049 this.indexMap = null;
48050 var s = this.getScrollState();
48051 this.refresh(true);
48052 this.restoreScroll(s);
48053 this.afterMove(newIndex);
48056 afterMove : function(colIndex){
48057 if(this.enableMoveAnim && Roo.enableFx){
48058 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48062 updateCell : function(dm, rowIndex, dataIndex){
48063 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48064 if(typeof colIndex == "undefined"){ // not present in grid
48067 var cm = this.grid.colModel;
48068 var cell = this.getCell(rowIndex, colIndex);
48069 var cellText = this.getCellText(rowIndex, colIndex);
48072 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48073 id : cm.getColumnId(colIndex),
48074 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48076 var renderer = cm.getRenderer(colIndex);
48077 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48078 if(typeof val == "undefined" || val === "") val = " ";
48079 cellText.innerHTML = val;
48080 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48081 this.syncRowHeights(rowIndex, rowIndex);
48084 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48086 if(this.grid.autoSizeHeaders){
48087 var h = this.getHeaderCellMeasure(colIndex);
48088 maxWidth = Math.max(maxWidth, h.scrollWidth);
48091 if(this.cm.isLocked(colIndex)){
48092 tb = this.getLockedTable();
48095 tb = this.getBodyTable();
48096 index = colIndex - this.cm.getLockedCount();
48099 var rows = tb.rows;
48100 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48101 for(var i = 0; i < stopIndex; i++){
48102 var cell = rows[i].childNodes[index].firstChild;
48103 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48106 return maxWidth + /*margin for error in IE*/ 5;
48109 * Autofit a column to its content.
48110 * @param {Number} colIndex
48111 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48113 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48114 if(this.cm.isHidden(colIndex)){
48115 return; // can't calc a hidden column
48118 var cid = this.cm.getColumnId(colIndex);
48119 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48120 if(this.grid.autoSizeHeaders){
48121 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48124 var newWidth = this.calcColumnWidth(colIndex);
48125 this.cm.setColumnWidth(colIndex,
48126 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48127 if(!suppressEvent){
48128 this.grid.fireEvent("columnresize", colIndex, newWidth);
48133 * Autofits all columns to their content and then expands to fit any extra space in the grid
48135 autoSizeColumns : function(){
48136 var cm = this.grid.colModel;
48137 var colCount = cm.getColumnCount();
48138 for(var i = 0; i < colCount; i++){
48139 this.autoSizeColumn(i, true, true);
48141 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48144 this.updateColumns();
48150 * Autofits all columns to the grid's width proportionate with their current size
48151 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48153 fitColumns : function(reserveScrollSpace){
48154 var cm = this.grid.colModel;
48155 var colCount = cm.getColumnCount();
48159 for (i = 0; i < colCount; i++){
48160 if(!cm.isHidden(i) && !cm.isFixed(i)){
48161 w = cm.getColumnWidth(i);
48167 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48168 if(reserveScrollSpace){
48171 var frac = (avail - cm.getTotalWidth())/width;
48172 while (cols.length){
48175 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48177 this.updateColumns();
48181 onRowSelect : function(rowIndex){
48182 var row = this.getRowComposite(rowIndex);
48183 row.addClass("x-grid-row-selected");
48186 onRowDeselect : function(rowIndex){
48187 var row = this.getRowComposite(rowIndex);
48188 row.removeClass("x-grid-row-selected");
48191 onCellSelect : function(row, col){
48192 var cell = this.getCell(row, col);
48194 Roo.fly(cell).addClass("x-grid-cell-selected");
48198 onCellDeselect : function(row, col){
48199 var cell = this.getCell(row, col);
48201 Roo.fly(cell).removeClass("x-grid-cell-selected");
48205 updateHeaderSortState : function(){
48206 var state = this.ds.getSortState();
48210 this.sortState = state;
48211 var sortColumn = this.cm.findColumnIndex(state.field);
48212 if(sortColumn != -1){
48213 var sortDir = state.direction;
48214 var sc = this.sortClasses;
48215 var hds = this.el.select(this.headerSelector).removeClass(sc);
48216 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48220 handleHeaderClick : function(g, index){
48221 if(this.headersDisabled){
48224 var dm = g.dataSource, cm = g.colModel;
48225 if(!cm.isSortable(index)){
48229 dm.sort(cm.getDataIndex(index));
48233 destroy : function(){
48235 this.colMenu.removeAll();
48236 Roo.menu.MenuMgr.unregister(this.colMenu);
48237 this.colMenu.getEl().remove();
48238 delete this.colMenu;
48241 this.hmenu.removeAll();
48242 Roo.menu.MenuMgr.unregister(this.hmenu);
48243 this.hmenu.getEl().remove();
48246 if(this.grid.enableColumnMove){
48247 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48249 for(var dd in dds){
48250 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48251 var elid = dds[dd].dragElId;
48253 Roo.get(elid).remove();
48254 } else if(dds[dd].config.isTarget){
48255 dds[dd].proxyTop.remove();
48256 dds[dd].proxyBottom.remove();
48259 if(Roo.dd.DDM.locationCache[dd]){
48260 delete Roo.dd.DDM.locationCache[dd];
48263 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48266 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48267 this.bind(null, null);
48268 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48271 handleLockChange : function(){
48272 this.refresh(true);
48275 onDenyColumnLock : function(){
48279 onDenyColumnHide : function(){
48283 handleHdMenuClick : function(item){
48284 var index = this.hdCtxIndex;
48285 var cm = this.cm, ds = this.ds;
48288 ds.sort(cm.getDataIndex(index), "ASC");
48291 ds.sort(cm.getDataIndex(index), "DESC");
48294 var lc = cm.getLockedCount();
48295 if(cm.getColumnCount(true) <= lc+1){
48296 this.onDenyColumnLock();
48300 cm.setLocked(index, true, true);
48301 cm.moveColumn(index, lc);
48302 this.grid.fireEvent("columnmove", index, lc);
48304 cm.setLocked(index, true);
48308 var lc = cm.getLockedCount();
48309 if((lc-1) != index){
48310 cm.setLocked(index, false, true);
48311 cm.moveColumn(index, lc-1);
48312 this.grid.fireEvent("columnmove", index, lc-1);
48314 cm.setLocked(index, false);
48318 index = cm.getIndexById(item.id.substr(4));
48320 if(item.checked && cm.getColumnCount(true) <= 1){
48321 this.onDenyColumnHide();
48324 cm.setHidden(index, item.checked);
48330 beforeColMenuShow : function(){
48331 var cm = this.cm, colCount = cm.getColumnCount();
48332 this.colMenu.removeAll();
48333 for(var i = 0; i < colCount; i++){
48334 this.colMenu.add(new Roo.menu.CheckItem({
48335 id: "col-"+cm.getColumnId(i),
48336 text: cm.getColumnHeader(i),
48337 checked: !cm.isHidden(i),
48343 handleHdCtx : function(g, index, e){
48345 var hd = this.getHeaderCell(index);
48346 this.hdCtxIndex = index;
48347 var ms = this.hmenu.items, cm = this.cm;
48348 ms.get("asc").setDisabled(!cm.isSortable(index));
48349 ms.get("desc").setDisabled(!cm.isSortable(index));
48350 if(this.grid.enableColLock !== false){
48351 ms.get("lock").setDisabled(cm.isLocked(index));
48352 ms.get("unlock").setDisabled(!cm.isLocked(index));
48354 this.hmenu.show(hd, "tl-bl");
48357 handleHdOver : function(e){
48358 var hd = this.findHeaderCell(e.getTarget());
48359 if(hd && !this.headersDisabled){
48360 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48361 this.fly(hd).addClass("x-grid-hd-over");
48366 handleHdOut : function(e){
48367 var hd = this.findHeaderCell(e.getTarget());
48369 this.fly(hd).removeClass("x-grid-hd-over");
48373 handleSplitDblClick : function(e, t){
48374 var i = this.getCellIndex(t);
48375 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48376 this.autoSizeColumn(i, true);
48381 render : function(){
48384 var colCount = cm.getColumnCount();
48386 if(this.grid.monitorWindowResize === true){
48387 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48389 var header = this.renderHeaders();
48390 var body = this.templates.body.apply({rows:""});
48391 var html = this.templates.master.apply({
48394 lockedHeader: header[0],
48398 //this.updateColumns();
48400 this.grid.getGridEl().dom.innerHTML = html;
48402 this.initElements();
48404 // a kludge to fix the random scolling effect in webkit
48405 this.el.on("scroll", function() {
48406 this.el.dom.scrollTop=0; // hopefully not recursive..
48409 this.scroller.on("scroll", this.handleScroll, this);
48410 this.lockedBody.on("mousewheel", this.handleWheel, this);
48411 this.mainBody.on("mousewheel", this.handleWheel, this);
48413 this.mainHd.on("mouseover", this.handleHdOver, this);
48414 this.mainHd.on("mouseout", this.handleHdOut, this);
48415 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48416 {delegate: "."+this.splitClass});
48418 this.lockedHd.on("mouseover", this.handleHdOver, this);
48419 this.lockedHd.on("mouseout", this.handleHdOut, this);
48420 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48421 {delegate: "."+this.splitClass});
48423 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48424 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48427 this.updateSplitters();
48429 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48430 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48431 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48434 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48435 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48437 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48438 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48440 if(this.grid.enableColLock !== false){
48441 this.hmenu.add('-',
48442 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48443 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48446 if(this.grid.enableColumnHide !== false){
48448 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48449 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48450 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48452 this.hmenu.add('-',
48453 {id:"columns", text: this.columnsText, menu: this.colMenu}
48456 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48458 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48461 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48462 this.dd = new Roo.grid.GridDragZone(this.grid, {
48463 ddGroup : this.grid.ddGroup || 'GridDD'
48468 for(var i = 0; i < colCount; i++){
48469 if(cm.isHidden(i)){
48470 this.hideColumn(i);
48472 if(cm.config[i].align){
48473 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48474 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48478 this.updateHeaderSortState();
48480 this.beforeInitialResize();
48483 // two part rendering gives faster view to the user
48484 this.renderPhase2.defer(1, this);
48487 renderPhase2 : function(){
48488 // render the rows now
48490 if(this.grid.autoSizeColumns){
48491 this.autoSizeColumns();
48495 beforeInitialResize : function(){
48499 onColumnSplitterMoved : function(i, w){
48500 this.userResized = true;
48501 var cm = this.grid.colModel;
48502 cm.setColumnWidth(i, w, true);
48503 var cid = cm.getColumnId(i);
48504 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48505 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48506 this.updateSplitters();
48508 this.grid.fireEvent("columnresize", i, w);
48511 syncRowHeights : function(startIndex, endIndex){
48512 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48513 startIndex = startIndex || 0;
48514 var mrows = this.getBodyTable().rows;
48515 var lrows = this.getLockedTable().rows;
48516 var len = mrows.length-1;
48517 endIndex = Math.min(endIndex || len, len);
48518 for(var i = startIndex; i <= endIndex; i++){
48519 var m = mrows[i], l = lrows[i];
48520 var h = Math.max(m.offsetHeight, l.offsetHeight);
48521 m.style.height = l.style.height = h + "px";
48526 layout : function(initialRender, is2ndPass){
48528 var auto = g.autoHeight;
48529 var scrollOffset = 16;
48530 var c = g.getGridEl(), cm = this.cm,
48531 expandCol = g.autoExpandColumn,
48533 //c.beginMeasure();
48535 if(!c.dom.offsetWidth){ // display:none?
48537 this.lockedWrap.show();
48538 this.mainWrap.show();
48543 var hasLock = this.cm.isLocked(0);
48545 var tbh = this.headerPanel.getHeight();
48546 var bbh = this.footerPanel.getHeight();
48549 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
48550 var newHeight = ch + c.getBorderWidth("tb");
48552 newHeight = Math.min(g.maxHeight, newHeight);
48554 c.setHeight(newHeight);
48558 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48561 var s = this.scroller;
48563 var csize = c.getSize(true);
48565 this.el.setSize(csize.width, csize.height);
48567 this.headerPanel.setWidth(csize.width);
48568 this.footerPanel.setWidth(csize.width);
48570 var hdHeight = this.mainHd.getHeight();
48571 var vw = csize.width;
48572 var vh = csize.height - (tbh + bbh);
48576 var bt = this.getBodyTable();
48577 var ltWidth = hasLock ?
48578 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
48580 var scrollHeight = bt.offsetHeight;
48581 var scrollWidth = ltWidth + bt.offsetWidth;
48582 var vscroll = false, hscroll = false;
48584 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
48586 var lw = this.lockedWrap, mw = this.mainWrap;
48587 var lb = this.lockedBody, mb = this.mainBody;
48589 setTimeout(function(){
48590 var t = s.dom.offsetTop;
48591 var w = s.dom.clientWidth,
48592 h = s.dom.clientHeight;
48595 lw.setSize(ltWidth, h);
48597 mw.setLeftTop(ltWidth, t);
48598 mw.setSize(w-ltWidth, h);
48600 lb.setHeight(h-hdHeight);
48601 mb.setHeight(h-hdHeight);
48603 if(is2ndPass !== true && !gv.userResized && expandCol){
48604 // high speed resize without full column calculation
48606 var ci = cm.getIndexById(expandCol);
48608 ci = cm.findColumnIndex(expandCol);
48610 ci = Math.max(0, ci); // make sure it's got at least the first col.
48611 var expandId = cm.getColumnId(ci);
48612 var tw = cm.getTotalWidth(false);
48613 var currentWidth = cm.getColumnWidth(ci);
48614 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
48615 if(currentWidth != cw){
48616 cm.setColumnWidth(ci, cw, true);
48617 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48618 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48619 gv.updateSplitters();
48620 gv.layout(false, true);
48632 onWindowResize : function(){
48633 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
48639 appendFooter : function(parentEl){
48643 sortAscText : "Sort Ascending",
48644 sortDescText : "Sort Descending",
48645 lockText : "Lock Column",
48646 unlockText : "Unlock Column",
48647 columnsText : "Columns"
48651 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
48652 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
48653 this.proxy.el.addClass('x-grid3-col-dd');
48656 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
48657 handleMouseDown : function(e){
48661 callHandleMouseDown : function(e){
48662 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
48667 * Ext JS Library 1.1.1
48668 * Copyright(c) 2006-2007, Ext JS, LLC.
48670 * Originally Released Under LGPL - original licence link has changed is not relivant.
48673 * <script type="text/javascript">
48677 // This is a support class used internally by the Grid components
48678 Roo.grid.SplitDragZone = function(grid, hd, hd2){
48680 this.view = grid.getView();
48681 this.proxy = this.view.resizeProxy;
48682 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
48683 "gridSplitters" + this.grid.getGridEl().id, {
48684 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
48686 this.setHandleElId(Roo.id(hd));
48687 this.setOuterHandleElId(Roo.id(hd2));
48688 this.scroll = false;
48690 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
48691 fly: Roo.Element.fly,
48693 b4StartDrag : function(x, y){
48694 this.view.headersDisabled = true;
48695 this.proxy.setHeight(this.view.mainWrap.getHeight());
48696 var w = this.cm.getColumnWidth(this.cellIndex);
48697 var minw = Math.max(w-this.grid.minColumnWidth, 0);
48698 this.resetConstraints();
48699 this.setXConstraint(minw, 1000);
48700 this.setYConstraint(0, 0);
48701 this.minX = x - minw;
48702 this.maxX = x + 1000;
48704 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
48708 handleMouseDown : function(e){
48709 ev = Roo.EventObject.setEvent(e);
48710 var t = this.fly(ev.getTarget());
48711 if(t.hasClass("x-grid-split")){
48712 this.cellIndex = this.view.getCellIndex(t.dom);
48713 this.split = t.dom;
48714 this.cm = this.grid.colModel;
48715 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
48716 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
48721 endDrag : function(e){
48722 this.view.headersDisabled = false;
48723 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
48724 var diff = endX - this.startPos;
48725 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
48728 autoOffset : function(){
48729 this.setDelta(0,0);
48733 * Ext JS Library 1.1.1
48734 * Copyright(c) 2006-2007, Ext JS, LLC.
48736 * Originally Released Under LGPL - original licence link has changed is not relivant.
48739 * <script type="text/javascript">
48743 // This is a support class used internally by the Grid components
48744 Roo.grid.GridDragZone = function(grid, config){
48745 this.view = grid.getView();
48746 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
48747 if(this.view.lockedBody){
48748 this.setHandleElId(Roo.id(this.view.mainBody.dom));
48749 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
48751 this.scroll = false;
48753 this.ddel = document.createElement('div');
48754 this.ddel.className = 'x-grid-dd-wrap';
48757 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
48758 ddGroup : "GridDD",
48760 getDragData : function(e){
48761 var t = Roo.lib.Event.getTarget(e);
48762 var rowIndex = this.view.findRowIndex(t);
48763 if(rowIndex !== false){
48764 var sm = this.grid.selModel;
48765 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
48766 // sm.mouseDown(e, t);
48768 if (e.hasModifier()){
48769 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
48771 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
48776 onInitDrag : function(e){
48777 var data = this.dragData;
48778 this.ddel.innerHTML = this.grid.getDragDropText();
48779 this.proxy.update(this.ddel);
48780 // fire start drag?
48783 afterRepair : function(){
48784 this.dragging = false;
48787 getRepairXY : function(e, data){
48791 onEndDrag : function(data, e){
48795 onValidDrop : function(dd, e, id){
48800 beforeInvalidDrop : function(e, id){
48805 * Ext JS Library 1.1.1
48806 * Copyright(c) 2006-2007, Ext JS, LLC.
48808 * Originally Released Under LGPL - original licence link has changed is not relivant.
48811 * <script type="text/javascript">
48816 * @class Roo.grid.ColumnModel
48817 * @extends Roo.util.Observable
48818 * This is the default implementation of a ColumnModel used by the Grid. It defines
48819 * the columns in the grid.
48822 var colModel = new Roo.grid.ColumnModel([
48823 {header: "Ticker", width: 60, sortable: true, locked: true},
48824 {header: "Company Name", width: 150, sortable: true},
48825 {header: "Market Cap.", width: 100, sortable: true},
48826 {header: "$ Sales", width: 100, sortable: true, renderer: money},
48827 {header: "Employees", width: 100, sortable: true, resizable: false}
48832 * The config options listed for this class are options which may appear in each
48833 * individual column definition.
48834 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
48836 * @param {Object} config An Array of column config objects. See this class's
48837 * config objects for details.
48839 Roo.grid.ColumnModel = function(config){
48841 * The config passed into the constructor
48843 this.config = config;
48846 // if no id, create one
48847 // if the column does not have a dataIndex mapping,
48848 // map it to the order it is in the config
48849 for(var i = 0, len = config.length; i < len; i++){
48851 if(typeof c.dataIndex == "undefined"){
48854 if(typeof c.renderer == "string"){
48855 c.renderer = Roo.util.Format[c.renderer];
48857 if(typeof c.id == "undefined"){
48860 if(c.editor && c.editor.xtype){
48861 c.editor = Roo.factory(c.editor, Roo.grid);
48863 if(c.editor && c.editor.isFormField){
48864 c.editor = new Roo.grid.GridEditor(c.editor);
48866 this.lookup[c.id] = c;
48870 * The width of columns which have no width specified (defaults to 100)
48873 this.defaultWidth = 100;
48876 * Default sortable of columns which have no sortable specified (defaults to false)
48879 this.defaultSortable = false;
48883 * @event widthchange
48884 * Fires when the width of a column changes.
48885 * @param {ColumnModel} this
48886 * @param {Number} columnIndex The column index
48887 * @param {Number} newWidth The new width
48889 "widthchange": true,
48891 * @event headerchange
48892 * Fires when the text of a header changes.
48893 * @param {ColumnModel} this
48894 * @param {Number} columnIndex The column index
48895 * @param {Number} newText The new header text
48897 "headerchange": true,
48899 * @event hiddenchange
48900 * Fires when a column is hidden or "unhidden".
48901 * @param {ColumnModel} this
48902 * @param {Number} columnIndex The column index
48903 * @param {Boolean} hidden true if hidden, false otherwise
48905 "hiddenchange": true,
48907 * @event columnmoved
48908 * Fires when a column is moved.
48909 * @param {ColumnModel} this
48910 * @param {Number} oldIndex
48911 * @param {Number} newIndex
48913 "columnmoved" : true,
48915 * @event columlockchange
48916 * Fires when a column's locked state is changed
48917 * @param {ColumnModel} this
48918 * @param {Number} colIndex
48919 * @param {Boolean} locked true if locked
48921 "columnlockchange" : true
48923 Roo.grid.ColumnModel.superclass.constructor.call(this);
48925 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
48927 * @cfg {String} header The header text to display in the Grid view.
48930 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
48931 * {@link Roo.data.Record} definition from which to draw the column's value. If not
48932 * specified, the column's index is used as an index into the Record's data Array.
48935 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
48936 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
48939 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
48940 * Defaults to the value of the {@link #defaultSortable} property.
48941 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
48944 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
48947 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
48950 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
48953 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
48956 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
48957 * given the cell's data value. See {@link #setRenderer}. If not specified, the
48958 * default renderer uses the raw data value.
48961 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
48964 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
48968 * Returns the id of the column at the specified index.
48969 * @param {Number} index The column index
48970 * @return {String} the id
48972 getColumnId : function(index){
48973 return this.config[index].id;
48977 * Returns the column for a specified id.
48978 * @param {String} id The column id
48979 * @return {Object} the column
48981 getColumnById : function(id){
48982 return this.lookup[id];
48987 * Returns the column for a specified dataIndex.
48988 * @param {String} dataIndex The column dataIndex
48989 * @return {Object|Boolean} the column or false if not found
48991 getColumnByDataIndex: function(dataIndex){
48992 var index = this.findColumnIndex(dataIndex);
48993 return index > -1 ? this.config[index] : false;
48997 * Returns the index for a specified column id.
48998 * @param {String} id The column id
48999 * @return {Number} the index, or -1 if not found
49001 getIndexById : function(id){
49002 for(var i = 0, len = this.config.length; i < len; i++){
49003 if(this.config[i].id == id){
49011 * Returns the index for a specified column dataIndex.
49012 * @param {String} dataIndex The column dataIndex
49013 * @return {Number} the index, or -1 if not found
49016 findColumnIndex : function(dataIndex){
49017 for(var i = 0, len = this.config.length; i < len; i++){
49018 if(this.config[i].dataIndex == dataIndex){
49026 moveColumn : function(oldIndex, newIndex){
49027 var c = this.config[oldIndex];
49028 this.config.splice(oldIndex, 1);
49029 this.config.splice(newIndex, 0, c);
49030 this.dataMap = null;
49031 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49034 isLocked : function(colIndex){
49035 return this.config[colIndex].locked === true;
49038 setLocked : function(colIndex, value, suppressEvent){
49039 if(this.isLocked(colIndex) == value){
49042 this.config[colIndex].locked = value;
49043 if(!suppressEvent){
49044 this.fireEvent("columnlockchange", this, colIndex, value);
49048 getTotalLockedWidth : function(){
49049 var totalWidth = 0;
49050 for(var i = 0; i < this.config.length; i++){
49051 if(this.isLocked(i) && !this.isHidden(i)){
49052 this.totalWidth += this.getColumnWidth(i);
49058 getLockedCount : function(){
49059 for(var i = 0, len = this.config.length; i < len; i++){
49060 if(!this.isLocked(i)){
49067 * Returns the number of columns.
49070 getColumnCount : function(visibleOnly){
49071 if(visibleOnly === true){
49073 for(var i = 0, len = this.config.length; i < len; i++){
49074 if(!this.isHidden(i)){
49080 return this.config.length;
49084 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49085 * @param {Function} fn
49086 * @param {Object} scope (optional)
49087 * @return {Array} result
49089 getColumnsBy : function(fn, scope){
49091 for(var i = 0, len = this.config.length; i < len; i++){
49092 var c = this.config[i];
49093 if(fn.call(scope||this, c, i) === true){
49101 * Returns true if the specified column is sortable.
49102 * @param {Number} col The column index
49103 * @return {Boolean}
49105 isSortable : function(col){
49106 if(typeof this.config[col].sortable == "undefined"){
49107 return this.defaultSortable;
49109 return this.config[col].sortable;
49113 * Returns the rendering (formatting) function defined for the column.
49114 * @param {Number} col The column index.
49115 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49117 getRenderer : function(col){
49118 if(!this.config[col].renderer){
49119 return Roo.grid.ColumnModel.defaultRenderer;
49121 return this.config[col].renderer;
49125 * Sets the rendering (formatting) function for a column.
49126 * @param {Number} col The column index
49127 * @param {Function} fn The function to use to process the cell's raw data
49128 * to return HTML markup for the grid view. The render function is called with
49129 * the following parameters:<ul>
49130 * <li>Data value.</li>
49131 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49132 * <li>css A CSS style string to apply to the table cell.</li>
49133 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49134 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49135 * <li>Row index</li>
49136 * <li>Column index</li>
49137 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49139 setRenderer : function(col, fn){
49140 this.config[col].renderer = fn;
49144 * Returns the width for the specified column.
49145 * @param {Number} col The column index
49148 getColumnWidth : function(col){
49149 return this.config[col].width || this.defaultWidth;
49153 * Sets the width for a column.
49154 * @param {Number} col The column index
49155 * @param {Number} width The new width
49157 setColumnWidth : function(col, width, suppressEvent){
49158 this.config[col].width = width;
49159 this.totalWidth = null;
49160 if(!suppressEvent){
49161 this.fireEvent("widthchange", this, col, width);
49166 * Returns the total width of all columns.
49167 * @param {Boolean} includeHidden True to include hidden column widths
49170 getTotalWidth : function(includeHidden){
49171 if(!this.totalWidth){
49172 this.totalWidth = 0;
49173 for(var i = 0, len = this.config.length; i < len; i++){
49174 if(includeHidden || !this.isHidden(i)){
49175 this.totalWidth += this.getColumnWidth(i);
49179 return this.totalWidth;
49183 * Returns the header for the specified column.
49184 * @param {Number} col The column index
49187 getColumnHeader : function(col){
49188 return this.config[col].header;
49192 * Sets the header for a column.
49193 * @param {Number} col The column index
49194 * @param {String} header The new header
49196 setColumnHeader : function(col, header){
49197 this.config[col].header = header;
49198 this.fireEvent("headerchange", this, col, header);
49202 * Returns the tooltip for the specified column.
49203 * @param {Number} col The column index
49206 getColumnTooltip : function(col){
49207 return this.config[col].tooltip;
49210 * Sets the tooltip for a column.
49211 * @param {Number} col The column index
49212 * @param {String} tooltip The new tooltip
49214 setColumnTooltip : function(col, tooltip){
49215 this.config[col].tooltip = tooltip;
49219 * Returns the dataIndex for the specified column.
49220 * @param {Number} col The column index
49223 getDataIndex : function(col){
49224 return this.config[col].dataIndex;
49228 * Sets the dataIndex for a column.
49229 * @param {Number} col The column index
49230 * @param {Number} dataIndex The new dataIndex
49232 setDataIndex : function(col, dataIndex){
49233 this.config[col].dataIndex = dataIndex;
49239 * Returns true if the cell is editable.
49240 * @param {Number} colIndex The column index
49241 * @param {Number} rowIndex The row index
49242 * @return {Boolean}
49244 isCellEditable : function(colIndex, rowIndex){
49245 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49249 * Returns the editor defined for the cell/column.
49250 * return false or null to disable editing.
49251 * @param {Number} colIndex The column index
49252 * @param {Number} rowIndex The row index
49255 getCellEditor : function(colIndex, rowIndex){
49256 return this.config[colIndex].editor;
49260 * Sets if a column is editable.
49261 * @param {Number} col The column index
49262 * @param {Boolean} editable True if the column is editable
49264 setEditable : function(col, editable){
49265 this.config[col].editable = editable;
49270 * Returns true if the column is hidden.
49271 * @param {Number} colIndex The column index
49272 * @return {Boolean}
49274 isHidden : function(colIndex){
49275 return this.config[colIndex].hidden;
49280 * Returns true if the column width cannot be changed
49282 isFixed : function(colIndex){
49283 return this.config[colIndex].fixed;
49287 * Returns true if the column can be resized
49288 * @return {Boolean}
49290 isResizable : function(colIndex){
49291 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49294 * Sets if a column is hidden.
49295 * @param {Number} colIndex The column index
49296 * @param {Boolean} hidden True if the column is hidden
49298 setHidden : function(colIndex, hidden){
49299 this.config[colIndex].hidden = hidden;
49300 this.totalWidth = null;
49301 this.fireEvent("hiddenchange", this, colIndex, hidden);
49305 * Sets the editor for a column.
49306 * @param {Number} col The column index
49307 * @param {Object} editor The editor object
49309 setEditor : function(col, editor){
49310 this.config[col].editor = editor;
49314 Roo.grid.ColumnModel.defaultRenderer = function(value){
49315 if(typeof value == "string" && value.length < 1){
49321 // Alias for backwards compatibility
49322 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49325 * Ext JS Library 1.1.1
49326 * Copyright(c) 2006-2007, Ext JS, LLC.
49328 * Originally Released Under LGPL - original licence link has changed is not relivant.
49331 * <script type="text/javascript">
49335 * @class Roo.grid.AbstractSelectionModel
49336 * @extends Roo.util.Observable
49337 * Abstract base class for grid SelectionModels. It provides the interface that should be
49338 * implemented by descendant classes. This class should not be directly instantiated.
49341 Roo.grid.AbstractSelectionModel = function(){
49342 this.locked = false;
49343 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49346 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49347 /** @ignore Called by the grid automatically. Do not call directly. */
49348 init : function(grid){
49354 * Locks the selections.
49357 this.locked = true;
49361 * Unlocks the selections.
49363 unlock : function(){
49364 this.locked = false;
49368 * Returns true if the selections are locked.
49369 * @return {Boolean}
49371 isLocked : function(){
49372 return this.locked;
49376 * Ext JS Library 1.1.1
49377 * Copyright(c) 2006-2007, Ext JS, LLC.
49379 * Originally Released Under LGPL - original licence link has changed is not relivant.
49382 * <script type="text/javascript">
49385 * @extends Roo.grid.AbstractSelectionModel
49386 * @class Roo.grid.RowSelectionModel
49387 * The default SelectionModel used by {@link Roo.grid.Grid}.
49388 * It supports multiple selections and keyboard selection/navigation.
49390 * @param {Object} config
49392 Roo.grid.RowSelectionModel = function(config){
49393 Roo.apply(this, config);
49394 this.selections = new Roo.util.MixedCollection(false, function(o){
49399 this.lastActive = false;
49403 * @event selectionchange
49404 * Fires when the selection changes
49405 * @param {SelectionModel} this
49407 "selectionchange" : true,
49409 * @event afterselectionchange
49410 * Fires after the selection changes (eg. by key press or clicking)
49411 * @param {SelectionModel} this
49413 "afterselectionchange" : true,
49415 * @event beforerowselect
49416 * Fires when a row is selected being selected, return false to cancel.
49417 * @param {SelectionModel} this
49418 * @param {Number} rowIndex The selected index
49419 * @param {Boolean} keepExisting False if other selections will be cleared
49421 "beforerowselect" : true,
49424 * Fires when a row is selected.
49425 * @param {SelectionModel} this
49426 * @param {Number} rowIndex The selected index
49427 * @param {Roo.data.Record} r The record
49429 "rowselect" : true,
49431 * @event rowdeselect
49432 * Fires when a row is deselected.
49433 * @param {SelectionModel} this
49434 * @param {Number} rowIndex The selected index
49436 "rowdeselect" : true
49438 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49439 this.locked = false;
49442 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49444 * @cfg {Boolean} singleSelect
49445 * True to allow selection of only one row at a time (defaults to false)
49447 singleSelect : false,
49450 initEvents : function(){
49452 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49453 this.grid.on("mousedown", this.handleMouseDown, this);
49454 }else{ // allow click to work like normal
49455 this.grid.on("rowclick", this.handleDragableRowClick, this);
49458 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49459 "up" : function(e){
49461 this.selectPrevious(e.shiftKey);
49462 }else if(this.last !== false && this.lastActive !== false){
49463 var last = this.last;
49464 this.selectRange(this.last, this.lastActive-1);
49465 this.grid.getView().focusRow(this.lastActive);
49466 if(last !== false){
49470 this.selectFirstRow();
49472 this.fireEvent("afterselectionchange", this);
49474 "down" : function(e){
49476 this.selectNext(e.shiftKey);
49477 }else if(this.last !== false && this.lastActive !== false){
49478 var last = this.last;
49479 this.selectRange(this.last, this.lastActive+1);
49480 this.grid.getView().focusRow(this.lastActive);
49481 if(last !== false){
49485 this.selectFirstRow();
49487 this.fireEvent("afterselectionchange", this);
49492 var view = this.grid.view;
49493 view.on("refresh", this.onRefresh, this);
49494 view.on("rowupdated", this.onRowUpdated, this);
49495 view.on("rowremoved", this.onRemove, this);
49499 onRefresh : function(){
49500 var ds = this.grid.dataSource, i, v = this.grid.view;
49501 var s = this.selections;
49502 s.each(function(r){
49503 if((i = ds.indexOfId(r.id)) != -1){
49512 onRemove : function(v, index, r){
49513 this.selections.remove(r);
49517 onRowUpdated : function(v, index, r){
49518 if(this.isSelected(r)){
49519 v.onRowSelect(index);
49525 * @param {Array} records The records to select
49526 * @param {Boolean} keepExisting (optional) True to keep existing selections
49528 selectRecords : function(records, keepExisting){
49530 this.clearSelections();
49532 var ds = this.grid.dataSource;
49533 for(var i = 0, len = records.length; i < len; i++){
49534 this.selectRow(ds.indexOf(records[i]), true);
49539 * Gets the number of selected rows.
49542 getCount : function(){
49543 return this.selections.length;
49547 * Selects the first row in the grid.
49549 selectFirstRow : function(){
49554 * Select the last row.
49555 * @param {Boolean} keepExisting (optional) True to keep existing selections
49557 selectLastRow : function(keepExisting){
49558 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
49562 * Selects the row immediately following the last selected row.
49563 * @param {Boolean} keepExisting (optional) True to keep existing selections
49565 selectNext : function(keepExisting){
49566 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49567 this.selectRow(this.last+1, keepExisting);
49568 this.grid.getView().focusRow(this.last);
49573 * Selects the row that precedes the last selected row.
49574 * @param {Boolean} keepExisting (optional) True to keep existing selections
49576 selectPrevious : function(keepExisting){
49578 this.selectRow(this.last-1, keepExisting);
49579 this.grid.getView().focusRow(this.last);
49584 * Returns the selected records
49585 * @return {Array} Array of selected records
49587 getSelections : function(){
49588 return [].concat(this.selections.items);
49592 * Returns the first selected record.
49595 getSelected : function(){
49596 return this.selections.itemAt(0);
49601 * Clears all selections.
49603 clearSelections : function(fast){
49604 if(this.locked) return;
49606 var ds = this.grid.dataSource;
49607 var s = this.selections;
49608 s.each(function(r){
49609 this.deselectRow(ds.indexOfId(r.id));
49613 this.selections.clear();
49620 * Selects all rows.
49622 selectAll : function(){
49623 if(this.locked) return;
49624 this.selections.clear();
49625 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
49626 this.selectRow(i, true);
49631 * Returns True if there is a selection.
49632 * @return {Boolean}
49634 hasSelection : function(){
49635 return this.selections.length > 0;
49639 * Returns True if the specified row is selected.
49640 * @param {Number/Record} record The record or index of the record to check
49641 * @return {Boolean}
49643 isSelected : function(index){
49644 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
49645 return (r && this.selections.key(r.id) ? true : false);
49649 * Returns True if the specified record id is selected.
49650 * @param {String} id The id of record to check
49651 * @return {Boolean}
49653 isIdSelected : function(id){
49654 return (this.selections.key(id) ? true : false);
49658 handleMouseDown : function(e, t){
49659 var view = this.grid.getView(), rowIndex;
49660 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
49663 if(e.shiftKey && this.last !== false){
49664 var last = this.last;
49665 this.selectRange(last, rowIndex, e.ctrlKey);
49666 this.last = last; // reset the last
49667 view.focusRow(rowIndex);
49669 var isSelected = this.isSelected(rowIndex);
49670 if(e.button !== 0 && isSelected){
49671 view.focusRow(rowIndex);
49672 }else if(e.ctrlKey && isSelected){
49673 this.deselectRow(rowIndex);
49674 }else if(!isSelected){
49675 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
49676 view.focusRow(rowIndex);
49679 this.fireEvent("afterselectionchange", this);
49682 handleDragableRowClick : function(grid, rowIndex, e)
49684 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
49685 this.selectRow(rowIndex, false);
49686 grid.view.focusRow(rowIndex);
49687 this.fireEvent("afterselectionchange", this);
49692 * Selects multiple rows.
49693 * @param {Array} rows Array of the indexes of the row to select
49694 * @param {Boolean} keepExisting (optional) True to keep existing selections
49696 selectRows : function(rows, keepExisting){
49698 this.clearSelections();
49700 for(var i = 0, len = rows.length; i < len; i++){
49701 this.selectRow(rows[i], true);
49706 * Selects a range of rows. All rows in between startRow and endRow are also selected.
49707 * @param {Number} startRow The index of the first row in the range
49708 * @param {Number} endRow The index of the last row in the range
49709 * @param {Boolean} keepExisting (optional) True to retain existing selections
49711 selectRange : function(startRow, endRow, keepExisting){
49712 if(this.locked) return;
49714 this.clearSelections();
49716 if(startRow <= endRow){
49717 for(var i = startRow; i <= endRow; i++){
49718 this.selectRow(i, true);
49721 for(var i = startRow; i >= endRow; i--){
49722 this.selectRow(i, true);
49728 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
49729 * @param {Number} startRow The index of the first row in the range
49730 * @param {Number} endRow The index of the last row in the range
49732 deselectRange : function(startRow, endRow, preventViewNotify){
49733 if(this.locked) return;
49734 for(var i = startRow; i <= endRow; i++){
49735 this.deselectRow(i, preventViewNotify);
49741 * @param {Number} row The index of the row to select
49742 * @param {Boolean} keepExisting (optional) True to keep existing selections
49744 selectRow : function(index, keepExisting, preventViewNotify){
49745 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
49746 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
49747 if(!keepExisting || this.singleSelect){
49748 this.clearSelections();
49750 var r = this.grid.dataSource.getAt(index);
49751 this.selections.add(r);
49752 this.last = this.lastActive = index;
49753 if(!preventViewNotify){
49754 this.grid.getView().onRowSelect(index);
49756 this.fireEvent("rowselect", this, index, r);
49757 this.fireEvent("selectionchange", this);
49763 * @param {Number} row The index of the row to deselect
49765 deselectRow : function(index, preventViewNotify){
49766 if(this.locked) return;
49767 if(this.last == index){
49770 if(this.lastActive == index){
49771 this.lastActive = false;
49773 var r = this.grid.dataSource.getAt(index);
49774 this.selections.remove(r);
49775 if(!preventViewNotify){
49776 this.grid.getView().onRowDeselect(index);
49778 this.fireEvent("rowdeselect", this, index);
49779 this.fireEvent("selectionchange", this);
49783 restoreLast : function(){
49785 this.last = this._last;
49790 acceptsNav : function(row, col, cm){
49791 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49795 onEditorKey : function(field, e){
49796 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49801 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49803 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49805 }else if(k == e.ENTER && !e.ctrlKey){
49809 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
49811 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
49813 }else if(k == e.ESC){
49817 g.startEditing(newCell[0], newCell[1]);
49822 * Ext JS Library 1.1.1
49823 * Copyright(c) 2006-2007, Ext JS, LLC.
49825 * Originally Released Under LGPL - original licence link has changed is not relivant.
49828 * <script type="text/javascript">
49831 * @class Roo.grid.CellSelectionModel
49832 * @extends Roo.grid.AbstractSelectionModel
49833 * This class provides the basic implementation for cell selection in a grid.
49835 * @param {Object} config The object containing the configuration of this model.
49837 Roo.grid.CellSelectionModel = function(config){
49838 Roo.apply(this, config);
49840 this.selection = null;
49844 * @event beforerowselect
49845 * Fires before a cell is selected.
49846 * @param {SelectionModel} this
49847 * @param {Number} rowIndex The selected row index
49848 * @param {Number} colIndex The selected cell index
49850 "beforecellselect" : true,
49852 * @event cellselect
49853 * Fires when a cell is selected.
49854 * @param {SelectionModel} this
49855 * @param {Number} rowIndex The selected row index
49856 * @param {Number} colIndex The selected cell index
49858 "cellselect" : true,
49860 * @event selectionchange
49861 * Fires when the active selection changes.
49862 * @param {SelectionModel} this
49863 * @param {Object} selection null for no selection or an object (o) with two properties
49865 <li>o.record: the record object for the row the selection is in</li>
49866 <li>o.cell: An array of [rowIndex, columnIndex]</li>
49869 "selectionchange" : true
49871 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
49874 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
49877 initEvents : function(){
49878 this.grid.on("mousedown", this.handleMouseDown, this);
49879 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
49880 var view = this.grid.view;
49881 view.on("refresh", this.onViewChange, this);
49882 view.on("rowupdated", this.onRowUpdated, this);
49883 view.on("beforerowremoved", this.clearSelections, this);
49884 view.on("beforerowsinserted", this.clearSelections, this);
49885 if(this.grid.isEditor){
49886 this.grid.on("beforeedit", this.beforeEdit, this);
49891 beforeEdit : function(e){
49892 this.select(e.row, e.column, false, true, e.record);
49896 onRowUpdated : function(v, index, r){
49897 if(this.selection && this.selection.record == r){
49898 v.onCellSelect(index, this.selection.cell[1]);
49903 onViewChange : function(){
49904 this.clearSelections(true);
49908 * Returns the currently selected cell,.
49909 * @return {Array} The selected cell (row, column) or null if none selected.
49911 getSelectedCell : function(){
49912 return this.selection ? this.selection.cell : null;
49916 * Clears all selections.
49917 * @param {Boolean} true to prevent the gridview from being notified about the change.
49919 clearSelections : function(preventNotify){
49920 var s = this.selection;
49922 if(preventNotify !== true){
49923 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
49925 this.selection = null;
49926 this.fireEvent("selectionchange", this, null);
49931 * Returns true if there is a selection.
49932 * @return {Boolean}
49934 hasSelection : function(){
49935 return this.selection ? true : false;
49939 handleMouseDown : function(e, t){
49940 var v = this.grid.getView();
49941 if(this.isLocked()){
49944 var row = v.findRowIndex(t);
49945 var cell = v.findCellIndex(t);
49946 if(row !== false && cell !== false){
49947 this.select(row, cell);
49953 * @param {Number} rowIndex
49954 * @param {Number} collIndex
49956 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
49957 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
49958 this.clearSelections();
49959 r = r || this.grid.dataSource.getAt(rowIndex);
49962 cell : [rowIndex, colIndex]
49964 if(!preventViewNotify){
49965 var v = this.grid.getView();
49966 v.onCellSelect(rowIndex, colIndex);
49967 if(preventFocus !== true){
49968 v.focusCell(rowIndex, colIndex);
49971 this.fireEvent("cellselect", this, rowIndex, colIndex);
49972 this.fireEvent("selectionchange", this, this.selection);
49977 isSelectable : function(rowIndex, colIndex, cm){
49978 return !cm.isHidden(colIndex);
49982 handleKeyDown : function(e){
49983 Roo.log('Cell Sel Model handleKeyDown');
49984 if(!e.isNavKeyPress()){
49987 var g = this.grid, s = this.selection;
49990 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
49992 this.select(cell[0], cell[1]);
49997 var walk = function(row, col, step){
49998 return g.walkCells(row, col, step, sm.isSelectable, sm);
50000 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
50005 // handled by onEditorKey
50006 if (g.isEditor && g.editing) {
50010 newCell = walk(r, c-1, -1);
50012 newCell = walk(r, c+1, 1);
50016 newCell = walk(r+1, c, 1);
50019 newCell = walk(r-1, c, -1);
50022 newCell = walk(r, c+1, 1);
50025 newCell = walk(r, c-1, -1);
50028 if(g.isEditor && !g.editing){
50029 g.startEditing(r, c);
50036 this.select(newCell[0], newCell[1]);
50041 acceptsNav : function(row, col, cm){
50042 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50045 onEditorKey : function(field, e){
50047 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50048 ///Roo.log('onEditorKey' + k);
50052 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50054 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50057 }else if(k == e.ENTER && !e.ctrlKey){
50060 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50061 }else if(k == e.ESC){
50067 //Roo.log('next cell after edit');
50068 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50073 * Ext JS Library 1.1.1
50074 * Copyright(c) 2006-2007, Ext JS, LLC.
50076 * Originally Released Under LGPL - original licence link has changed is not relivant.
50079 * <script type="text/javascript">
50083 * @class Roo.grid.EditorGrid
50084 * @extends Roo.grid.Grid
50085 * Class for creating and editable grid.
50086 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50087 * The container MUST have some type of size defined for the grid to fill. The container will be
50088 * automatically set to position relative if it isn't already.
50089 * @param {Object} dataSource The data model to bind to
50090 * @param {Object} colModel The column model with info about this grid's columns
50092 Roo.grid.EditorGrid = function(container, config){
50093 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50094 this.getGridEl().addClass("xedit-grid");
50096 if(!this.selModel){
50097 this.selModel = new Roo.grid.CellSelectionModel();
50100 this.activeEditor = null;
50104 * @event beforeedit
50105 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50106 * <ul style="padding:5px;padding-left:16px;">
50107 * <li>grid - This grid</li>
50108 * <li>record - The record being edited</li>
50109 * <li>field - The field name being edited</li>
50110 * <li>value - The value for the field being edited.</li>
50111 * <li>row - The grid row index</li>
50112 * <li>column - The grid column index</li>
50113 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50115 * @param {Object} e An edit event (see above for description)
50117 "beforeedit" : true,
50120 * Fires after a cell is edited. <br />
50121 * <ul style="padding:5px;padding-left:16px;">
50122 * <li>grid - This grid</li>
50123 * <li>record - The record being edited</li>
50124 * <li>field - The field name being edited</li>
50125 * <li>value - The value being set</li>
50126 * <li>originalValue - The original value for the field, before the edit.</li>
50127 * <li>row - The grid row index</li>
50128 * <li>column - The grid column index</li>
50130 * @param {Object} e An edit event (see above for description)
50132 "afteredit" : true,
50134 * @event validateedit
50135 * Fires after a cell is edited, but before the value is set in the record.
50136 * You can use this to modify the value being set in the field, Return false
50137 * to cancel the change. The edit event object has the following properties <br />
50138 * <ul style="padding:5px;padding-left:16px;">
50139 * <li>editor - This editor</li>
50140 * <li>grid - This grid</li>
50141 * <li>record - The record being edited</li>
50142 * <li>field - The field name being edited</li>
50143 * <li>value - The value being set</li>
50144 * <li>originalValue - The original value for the field, before the edit.</li>
50145 * <li>row - The grid row index</li>
50146 * <li>column - The grid column index</li>
50147 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50149 * @param {Object} e An edit event (see above for description)
50151 "validateedit" : true
50153 this.on("bodyscroll", this.stopEditing, this);
50154 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50157 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50159 * @cfg {Number} clicksToEdit
50160 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50167 trackMouseOver: false, // causes very odd FF errors
50169 onCellDblClick : function(g, row, col){
50170 this.startEditing(row, col);
50173 onEditComplete : function(ed, value, startValue){
50174 this.editing = false;
50175 this.activeEditor = null;
50176 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50178 var field = this.colModel.getDataIndex(ed.col);
50183 originalValue: startValue,
50190 if(String(value) !== String(startValue)){
50192 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50193 r.set(field, e.value);
50194 // if we are dealing with a combo box..
50195 // then we also set the 'name' colum to be the displayField
50196 if (ed.field.displayField && ed.field.name) {
50197 r.set(ed.field.name, ed.field.el.dom.value);
50200 delete e.cancel; //?? why!!!
50201 this.fireEvent("afteredit", e);
50204 this.fireEvent("afteredit", e); // always fire it!
50206 this.view.focusCell(ed.row, ed.col);
50210 * Starts editing the specified for the specified row/column
50211 * @param {Number} rowIndex
50212 * @param {Number} colIndex
50214 startEditing : function(row, col){
50215 this.stopEditing();
50216 if(this.colModel.isCellEditable(col, row)){
50217 this.view.ensureVisible(row, col, true);
50218 var r = this.dataSource.getAt(row);
50219 var field = this.colModel.getDataIndex(col);
50224 value: r.data[field],
50229 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50230 this.editing = true;
50231 var ed = this.colModel.getCellEditor(col, row);
50237 ed.render(ed.parentEl || document.body);
50240 (function(){ // complex but required for focus issues in safari, ie and opera
50244 ed.on("complete", this.onEditComplete, this, {single: true});
50245 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50246 this.activeEditor = ed;
50247 var v = r.data[field];
50248 ed.startEdit(this.view.getCell(row, col), v);
50249 // combo's with 'displayField and name set
50250 if (ed.field.displayField && ed.field.name) {
50251 ed.field.el.dom.value = r.data[ed.field.name];
50255 }).defer(50, this);
50261 * Stops any active editing
50263 stopEditing : function(){
50264 if(this.activeEditor){
50265 this.activeEditor.completeEdit();
50267 this.activeEditor = null;
50271 * Ext JS Library 1.1.1
50272 * Copyright(c) 2006-2007, Ext JS, LLC.
50274 * Originally Released Under LGPL - original licence link has changed is not relivant.
50277 * <script type="text/javascript">
50280 // private - not really -- you end up using it !
50281 // This is a support class used internally by the Grid components
50284 * @class Roo.grid.GridEditor
50285 * @extends Roo.Editor
50286 * Class for creating and editable grid elements.
50287 * @param {Object} config any settings (must include field)
50289 Roo.grid.GridEditor = function(field, config){
50290 if (!config && field.field) {
50292 field = Roo.factory(config.field, Roo.form);
50294 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50295 field.monitorTab = false;
50298 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50301 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50304 alignment: "tl-tl",
50307 cls: "x-small-editor x-grid-editor",
50312 * Ext JS Library 1.1.1
50313 * Copyright(c) 2006-2007, Ext JS, LLC.
50315 * Originally Released Under LGPL - original licence link has changed is not relivant.
50318 * <script type="text/javascript">
50323 Roo.grid.PropertyRecord = Roo.data.Record.create([
50324 {name:'name',type:'string'}, 'value'
50328 Roo.grid.PropertyStore = function(grid, source){
50330 this.store = new Roo.data.Store({
50331 recordType : Roo.grid.PropertyRecord
50333 this.store.on('update', this.onUpdate, this);
50335 this.setSource(source);
50337 Roo.grid.PropertyStore.superclass.constructor.call(this);
50342 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50343 setSource : function(o){
50345 this.store.removeAll();
50348 if(this.isEditableValue(o[k])){
50349 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50352 this.store.loadRecords({records: data}, {}, true);
50355 onUpdate : function(ds, record, type){
50356 if(type == Roo.data.Record.EDIT){
50357 var v = record.data['value'];
50358 var oldValue = record.modified['value'];
50359 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50360 this.source[record.id] = v;
50362 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50369 getProperty : function(row){
50370 return this.store.getAt(row);
50373 isEditableValue: function(val){
50374 if(val && val instanceof Date){
50376 }else if(typeof val == 'object' || typeof val == 'function'){
50382 setValue : function(prop, value){
50383 this.source[prop] = value;
50384 this.store.getById(prop).set('value', value);
50387 getSource : function(){
50388 return this.source;
50392 Roo.grid.PropertyColumnModel = function(grid, store){
50395 g.PropertyColumnModel.superclass.constructor.call(this, [
50396 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50397 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50399 this.store = store;
50400 this.bselect = Roo.DomHelper.append(document.body, {
50401 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50402 {tag: 'option', value: 'true', html: 'true'},
50403 {tag: 'option', value: 'false', html: 'false'}
50406 Roo.id(this.bselect);
50409 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50410 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50411 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50412 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50413 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50415 this.renderCellDelegate = this.renderCell.createDelegate(this);
50416 this.renderPropDelegate = this.renderProp.createDelegate(this);
50419 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50423 valueText : 'Value',
50425 dateFormat : 'm/j/Y',
50428 renderDate : function(dateVal){
50429 return dateVal.dateFormat(this.dateFormat);
50432 renderBool : function(bVal){
50433 return bVal ? 'true' : 'false';
50436 isCellEditable : function(colIndex, rowIndex){
50437 return colIndex == 1;
50440 getRenderer : function(col){
50442 this.renderCellDelegate : this.renderPropDelegate;
50445 renderProp : function(v){
50446 return this.getPropertyName(v);
50449 renderCell : function(val){
50451 if(val instanceof Date){
50452 rv = this.renderDate(val);
50453 }else if(typeof val == 'boolean'){
50454 rv = this.renderBool(val);
50456 return Roo.util.Format.htmlEncode(rv);
50459 getPropertyName : function(name){
50460 var pn = this.grid.propertyNames;
50461 return pn && pn[name] ? pn[name] : name;
50464 getCellEditor : function(colIndex, rowIndex){
50465 var p = this.store.getProperty(rowIndex);
50466 var n = p.data['name'], val = p.data['value'];
50468 if(typeof(this.grid.customEditors[n]) == 'string'){
50469 return this.editors[this.grid.customEditors[n]];
50471 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50472 return this.grid.customEditors[n];
50474 if(val instanceof Date){
50475 return this.editors['date'];
50476 }else if(typeof val == 'number'){
50477 return this.editors['number'];
50478 }else if(typeof val == 'boolean'){
50479 return this.editors['boolean'];
50481 return this.editors['string'];
50487 * @class Roo.grid.PropertyGrid
50488 * @extends Roo.grid.EditorGrid
50489 * This class represents the interface of a component based property grid control.
50490 * <br><br>Usage:<pre><code>
50491 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50499 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50500 * The container MUST have some type of size defined for the grid to fill. The container will be
50501 * automatically set to position relative if it isn't already.
50502 * @param {Object} config A config object that sets properties on this grid.
50504 Roo.grid.PropertyGrid = function(container, config){
50505 config = config || {};
50506 var store = new Roo.grid.PropertyStore(this);
50507 this.store = store;
50508 var cm = new Roo.grid.PropertyColumnModel(this, store);
50509 store.store.sort('name', 'ASC');
50510 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50513 enableColLock:false,
50514 enableColumnMove:false,
50516 trackMouseOver: false,
50519 this.getGridEl().addClass('x-props-grid');
50520 this.lastEditRow = null;
50521 this.on('columnresize', this.onColumnResize, this);
50524 * @event beforepropertychange
50525 * Fires before a property changes (return false to stop?)
50526 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50527 * @param {String} id Record Id
50528 * @param {String} newval New Value
50529 * @param {String} oldval Old Value
50531 "beforepropertychange": true,
50533 * @event propertychange
50534 * Fires after a property changes
50535 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50536 * @param {String} id Record Id
50537 * @param {String} newval New Value
50538 * @param {String} oldval Old Value
50540 "propertychange": true
50542 this.customEditors = this.customEditors || {};
50544 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50547 * @cfg {Object} customEditors map of colnames=> custom editors.
50548 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50549 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50550 * false disables editing of the field.
50554 * @cfg {Object} propertyNames map of property Names to their displayed value
50557 render : function(){
50558 Roo.grid.PropertyGrid.superclass.render.call(this);
50559 this.autoSize.defer(100, this);
50562 autoSize : function(){
50563 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50565 this.view.fitColumns();
50569 onColumnResize : function(){
50570 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
50574 * Sets the data for the Grid
50575 * accepts a Key => Value object of all the elements avaiable.
50576 * @param {Object} data to appear in grid.
50578 setSource : function(source){
50579 this.store.setSource(source);
50583 * Gets all the data from the grid.
50584 * @return {Object} data data stored in grid
50586 getSource : function(){
50587 return this.store.getSource();
50591 * Ext JS Library 1.1.1
50592 * Copyright(c) 2006-2007, Ext JS, LLC.
50594 * Originally Released Under LGPL - original licence link has changed is not relivant.
50597 * <script type="text/javascript">
50601 * @class Roo.LoadMask
50602 * A simple utility class for generically masking elements while loading data. If the element being masked has
50603 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
50604 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
50605 * element's UpdateManager load indicator and will be destroyed after the initial load.
50607 * Create a new LoadMask
50608 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
50609 * @param {Object} config The config object
50611 Roo.LoadMask = function(el, config){
50612 this.el = Roo.get(el);
50613 Roo.apply(this, config);
50615 this.store.on('beforeload', this.onBeforeLoad, this);
50616 this.store.on('load', this.onLoad, this);
50617 this.store.on('loadexception', this.onLoad, this);
50618 this.removeMask = false;
50620 var um = this.el.getUpdateManager();
50621 um.showLoadIndicator = false; // disable the default indicator
50622 um.on('beforeupdate', this.onBeforeLoad, this);
50623 um.on('update', this.onLoad, this);
50624 um.on('failure', this.onLoad, this);
50625 this.removeMask = true;
50629 Roo.LoadMask.prototype = {
50631 * @cfg {Boolean} removeMask
50632 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
50633 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
50636 * @cfg {String} msg
50637 * The text to display in a centered loading message box (defaults to 'Loading...')
50639 msg : 'Loading...',
50641 * @cfg {String} msgCls
50642 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
50644 msgCls : 'x-mask-loading',
50647 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
50653 * Disables the mask to prevent it from being displayed
50655 disable : function(){
50656 this.disabled = true;
50660 * Enables the mask so that it can be displayed
50662 enable : function(){
50663 this.disabled = false;
50667 onLoad : function(){
50668 this.el.unmask(this.removeMask);
50672 onBeforeLoad : function(){
50673 if(!this.disabled){
50674 this.el.mask(this.msg, this.msgCls);
50679 destroy : function(){
50681 this.store.un('beforeload', this.onBeforeLoad, this);
50682 this.store.un('load', this.onLoad, this);
50683 this.store.un('loadexception', this.onLoad, this);
50685 var um = this.el.getUpdateManager();
50686 um.un('beforeupdate', this.onBeforeLoad, this);
50687 um.un('update', this.onLoad, this);
50688 um.un('failure', this.onLoad, this);
50693 * Ext JS Library 1.1.1
50694 * Copyright(c) 2006-2007, Ext JS, LLC.
50696 * Originally Released Under LGPL - original licence link has changed is not relivant.
50699 * <script type="text/javascript">
50701 Roo.XTemplate = function(){
50702 Roo.XTemplate.superclass.constructor.apply(this, arguments);
50705 s = ['<tpl>', s, '</tpl>'].join('');
50707 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
50709 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
50710 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
50711 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
50715 while(m = s.match(re)){
50716 var m2 = m[0].match(nameRe);
50717 var m3 = m[0].match(ifRe);
50718 var m4 = m[0].match(execRe);
50719 var exp = null, fn = null, exec = null;
50720 var name = m2 && m2[1] ? m2[1] : '';
50722 exp = m3 && m3[1] ? m3[1] : null;
50724 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
50728 exp = m4 && m4[1] ? m4[1] : null;
50730 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
50735 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
50736 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
50737 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
50747 s = s.replace(m[0], '{xtpl'+ id + '}');
50750 for(var i = tpls.length-1; i >= 0; --i){
50751 this.compileTpl(tpls[i]);
50753 this.master = tpls[tpls.length-1];
50756 Roo.extend(Roo.XTemplate, Roo.Template, {
50758 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
50760 applySubTemplate : function(id, values, parent){
50761 var t = this.tpls[id];
50762 if(t.test && !t.test.call(this, values, parent)){
50765 if(t.exec && t.exec.call(this, values, parent)){
50768 var vs = t.target ? t.target.call(this, values, parent) : values;
50769 parent = t.target ? values : parent;
50770 if(t.target && vs instanceof Array){
50772 for(var i = 0, len = vs.length; i < len; i++){
50773 buf[buf.length] = t.compiled.call(this, vs[i], parent);
50775 return buf.join('');
50777 return t.compiled.call(this, vs, parent);
50780 compileTpl : function(tpl){
50781 var fm = Roo.util.Format;
50782 var useF = this.disableFormats !== true;
50783 var sep = Roo.isGecko ? "+" : ",";
50784 var fn = function(m, name, format, args){
50785 if(name.substr(0, 4) == 'xtpl'){
50786 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
50789 if(name.indexOf('.') != -1){
50792 v = "values['" + name + "']";
50794 if(format && useF){
50795 args = args ? ',' + args : "";
50796 if(format.substr(0, 5) != "this."){
50797 format = "fm." + format + '(';
50799 format = 'this.call("'+ format.substr(5) + '", ';
50803 args= ''; format = "("+v+" === undefined ? '' : ";
50805 return "'"+ sep + format + v + args + ")"+sep+"'";
50808 // branched to use + in gecko and [].join() in others
50810 body = "tpl.compiled = function(values, parent){ return '" +
50811 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
50814 body = ["tpl.compiled = function(values, parent){ return ['"];
50815 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
50816 body.push("'].join('');};");
50817 body = body.join('');
50819 /** eval:var:zzzzzzz */
50824 applyTemplate : function(values){
50825 return this.master.compiled.call(this, values, {});
50829 apply : function(){
50830 return this.applyTemplate.apply(this, arguments);
50833 compile : function(){return this;}
50836 Roo.XTemplate.from = function(el){
50837 el = Roo.getDom(el);
50838 return new Roo.XTemplate(el.value || el.innerHTML);
50840 * Original code for Roojs - LGPL
50841 * <script type="text/javascript">
50845 * @class Roo.XComponent
50846 * A delayed Element creator...
50848 * Mypart.xyx = new Roo.XComponent({
50850 parent : 'Mypart.xyz', // empty == document.element.!!
50854 disabled : function() {}
50856 tree : function() { // return an tree of xtype declared components
50860 xtype : 'NestedLayoutPanel',
50865 * @extends Roo.util.Observable
50867 * @param cfg {Object} configuration of component
50870 Roo.XComponent = function(cfg) {
50871 Roo.apply(this, cfg);
50875 * Fires when this the componnt is built
50876 * @param {Roo.XComponent} c the component
50880 * @event buildcomplete
50881 * Fires on the top level element when all elements have been built
50882 * @param {Roo.XComponent} c the top level component.
50884 'buildcomplete' : true
50888 Roo.XComponent.register(this);
50889 this.modules = false;
50890 this.el = false; // where the layout goes..
50894 Roo.extend(Roo.XComponent, Roo.util.Observable, {
50897 * The created element (with Roo.factory())
50898 * @type {Roo.Layout}
50904 * for BC - use el in new code
50905 * @type {Roo.Layout}
50911 * for BC - use el in new code
50912 * @type {Roo.Layout}
50917 * @cfg {Function|boolean} disabled
50918 * If this module is disabled by some rule, return true from the funtion
50923 * @cfg {String} parent
50924 * Name of parent element which it get xtype added to..
50929 * @cfg {String} order
50930 * Used to set the order in which elements are created (usefull for multiple tabs)
50935 * @cfg {String} name
50936 * String to display while loading.
50940 * @cfg {Array} items
50941 * A single item array - the first element is the root of the tree..
50942 * It's done this way to stay compatible with the Xtype system...
50950 Roo.apply(Roo.XComponent, {
50953 * @property buildCompleted
50954 * True when the builder has completed building the interface.
50957 buildCompleted : false,
50960 * @property topModule
50961 * the upper most module - uses document.element as it's constructor.
50968 * @property modules
50969 * array of modules to be created by registration system.
50970 * @type Roo.XComponent
50977 * Register components to be built later.
50979 * This solves the following issues
50980 * - Building is not done on page load, but after an authentication process has occured.
50981 * - Interface elements are registered on page load
50982 * - Parent Interface elements may not be loaded before child, so this handles that..
50989 module : 'Pman.Tab.projectMgr',
50991 parent : 'Pman.layout',
50992 disabled : false, // or use a function..
50995 * * @param {Object} details about module
50997 register : function(obj) {
50998 this.modules.push(obj);
51002 * convert a string to an object..
51006 toObject : function(str)
51008 if (!str || typeof(str) == 'object') {
51011 var ar = str.split('.');
51015 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51017 throw "Module not found : " + str;
51019 Roo.each(ar, function(e) {
51020 if (typeof(o[e]) == 'undefined') {
51021 throw "Module not found : " + str;
51031 * move modules into their correct place in the tree..
51034 preBuild : function ()
51037 Roo.each(this.modules , function (obj)
51039 obj.parent = this.toObject(obj.parent);
51042 this.topModule = obj;
51046 if (!obj.parent.modules) {
51047 obj.parent.modules = new Roo.util.MixedCollection(false,
51048 function(o) { return o.order + '' }
51052 obj.parent.modules.add(obj);
51057 * make a list of modules to build.
51058 * @return {Array} list of modules.
51061 buildOrder : function()
51064 var cmp = function(a,b) {
51065 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51068 if (!this.topModule || !this.topModule.modules) {
51069 throw "No top level modules to build";
51072 // make a flat list in order of modules to build.
51073 var mods = [ this.topModule ];
51076 // add modules to their parents..
51077 var addMod = function(m) {
51078 // Roo.debug && Roo.log(m.modKey);
51082 m.modules.keySort('ASC', cmp );
51083 m.modules.each(addMod);
51085 // not sure if this is used any more..
51087 m.finalize.name = m.name + " (clean up) ";
51088 mods.push(m.finalize);
51092 this.topModule.modules.keySort('ASC', cmp );
51093 this.topModule.modules.each(addMod);
51098 * Build the registered modules.
51099 * @param {Object} parent element.
51100 * @param {Function} optional method to call after module has been added.
51108 var mods = this.buildOrder();
51110 //this.allmods = mods;
51111 //Roo.debug && Roo.log(mods);
51113 if (!mods.length) { // should not happen
51114 throw "NO modules!!!";
51119 // flash it up as modal - so we store the mask!?
51120 Roo.MessageBox.show({ title: 'loading' });
51121 Roo.MessageBox.show({
51122 title: "Please wait...",
51123 msg: "Building Interface...",
51130 var total = mods.length;
51133 var progressRun = function() {
51134 if (!mods.length) {
51135 Roo.debug && Roo.log('hide?');
51136 Roo.MessageBox.hide();
51137 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51141 var m = mods.shift();
51142 Roo.debug && Roo.log(m);
51143 if (typeof(m) == 'function') { // not sure if this is supported any more..
51145 return progressRun.defer(10, _this);
51148 Roo.MessageBox.updateProgress(
51149 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51151 (m.name ? (' - ' + m.name) : '')
51156 var disabled = (typeof(m.disabled) == 'function') ?
51157 m.disabled.call(m.module.disabled) : m.disabled;
51161 return progressRun(); // we do not update the display!
51165 // it's a top level one..
51166 var layoutbase = new Ext.BorderLayout(document.body, {
51172 tabPosition: 'top',
51173 //resizeTabs: true,
51174 alwaysShowTabs: true,
51178 var tree = m.tree();
51179 tree.region = 'center';
51180 m.el = layoutbase.addxtype(tree);
51182 m.layout = m.panel.layout;
51183 return progressRun.defer(10, _this);
51186 var tree = m.tree();
51187 tree.region = tree.region || m.region;
51188 m.el = m.parent.el.addxtype(tree);
51189 m.fireEvent('built', m);
51191 m.layout = m.panel.layout;
51192 progressRun.defer(10, _this);
51195 progressRun.defer(1, _this);
51205 //<script type="text/javascript">
51210 * @extends Roo.LayoutDialog
51211 * A generic Login Dialog..... - only one needed in theory!?!?
51213 * Fires XComponent builder on success...
51216 * username,password, lang = for login actions.
51217 * check = 1 for periodic checking that sesion is valid.
51218 * passwordRequest = email request password
51219 * logout = 1 = to logout
51221 * Affects: (this id="????" elements)
51222 * loading (removed) (used to indicate application is loading)
51223 * loading-mask (hides) (used to hide application when it's building loading)
51229 * Myapp.login = Roo.Login({
51245 Roo.Login = function(cfg)
51251 Roo.apply(this,cfg);
51253 Roo.onReady(function() {
51259 Roo.Login.superclass.constructor.call(this, this);
51260 //this.addxtype(this.items[0]);
51266 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51269 * @cfg {String} method
51270 * Method used to query for login details.
51275 * @cfg {String} url
51276 * URL to query login data. - eg. baseURL + '/Login.php'
51282 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51287 * @property checkFails
51288 * Number of times we have attempted to get authentication check, and failed.
51293 * @property intervalID
51294 * The window interval that does the constant login checking.
51300 onLoad : function() // called on page load...
51304 if (Roo.get('loading')) { // clear any loading indicator..
51305 Roo.get('loading').remove();
51308 //this.switchLang('en'); // set the language to english..
51311 success: function(response, opts) { // check successfull...
51313 var res = this.processResponse(response);
51314 this.checkFails =0;
51315 if (!res.success) { // error!
51316 this.checkFails = 5;
51317 //console.log('call failure');
51318 return this.failure(response,opts);
51321 if (!res.data.id) { // id=0 == login failure.
51322 return this.show();
51326 //console.log(success);
51327 this.fillAuth(res.data);
51328 this.checkFails =0;
51329 Roo.XComponent.build();
51331 failure : this.show
51337 check: function(cfg) // called every so often to refresh cookie etc..
51339 if (cfg.again) { // could be undefined..
51342 this.checkFails = 0;
51345 if (this.sending) {
51346 if ( this.checkFails > 4) {
51347 Roo.MessageBox.alert("Error",
51348 "Error getting authentication status. - try reloading, or wait a while", function() {
51349 _this.sending = false;
51354 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51357 this.sending = true;
51364 method: this.method,
51365 success: cfg.success || this.success,
51366 failure : cfg.failure || this.failure,
51376 window.onbeforeunload = function() { }; // false does not work for IE..
51386 failure : function() {
51387 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51388 document.location = document.location.toString() + '?ts=' + Math.random();
51392 success : function() {
51393 _this.user = false;
51394 this.checkFails =0;
51396 document.location = document.location.toString() + '?ts=' + Math.random();
51403 processResponse : function (response)
51407 res = Roo.decode(response.responseText);
51409 if (typeof(res) != 'object') {
51410 res = { success : false, errorMsg : res, errors : true };
51412 if (typeof(res.success) == 'undefined') {
51413 res.success = false;
51417 res = { success : false, errorMsg : response.responseText, errors : true };
51422 success : function(response, opts) // check successfull...
51424 this.sending = false;
51425 var res = this.processResponse(response);
51426 if (!res.success) {
51427 return this.failure(response, opts);
51429 if (!res.data || !res.data.id) {
51430 return this.failure(response,opts);
51432 //console.log(res);
51433 this.fillAuth(res.data);
51435 this.checkFails =0;
51440 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51442 this.authUser = -1;
51443 this.sending = false;
51444 var res = this.processResponse(response);
51445 //console.log(res);
51446 if ( this.checkFails > 2) {
51448 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51449 "Error getting authentication status. - try reloading");
51452 opts.callCfg.again = true;
51453 this.check.defer(1000, this, [ opts.callCfg ]);
51459 fillAuth: function(au) {
51460 this.startAuthCheck();
51461 this.authUserId = au.id;
51462 this.authUser = au;
51463 this.lastChecked = new Date();
51464 this.fireEvent('refreshed', au);
51465 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
51466 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
51467 au.lang = au.lang || 'en';
51468 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
51469 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
51470 this.switchLang(au.lang );
51473 // open system... - -on setyp..
51474 if (this.authUserId < 0) {
51475 Roo.MessageBox.alert("Warning",
51476 "This is an open system - please set up a admin user with a password.");
51479 //Pman.onload(); // which should do nothing if it's a re-auth result...
51484 startAuthCheck : function() // starter for timeout checking..
51486 if (this.intervalID) { // timer already in place...
51490 this.intervalID = window.setInterval(function() {
51491 _this.check(false);
51492 }, 120000); // every 120 secs = 2mins..
51498 switchLang : function (lang)
51500 _T = typeof(_T) == 'undefined' ? false : _T;
51501 if (!_T || !lang.length) {
51505 if (!_T && lang != 'en') {
51506 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51510 if (typeof(_T.en) == 'undefined') {
51512 Roo.apply(_T.en, _T);
51515 if (typeof(_T[lang]) == 'undefined') {
51516 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51521 Roo.apply(_T, _T[lang]);
51522 // just need to set the text values for everything...
51524 /* this will not work ...
51528 function formLabel(name, val) {
51529 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
51532 formLabel('password', "Password"+':');
51533 formLabel('username', "Email Address"+':');
51534 formLabel('lang', "Language"+':');
51535 this.dialog.setTitle("Login");
51536 this.dialog.buttons[0].setText("Forgot Password");
51537 this.dialog.buttons[1].setText("Login");
51556 collapsible: false,
51558 center: { // needed??
51561 // tabPosition: 'top',
51564 alwaysShowTabs: false
51568 show : function(dlg)
51570 //console.log(this);
51571 this.form = this.layout.getRegion('center').activePanel.form;
51572 this.form.dialog = dlg;
51573 this.buttons[0].form = this.form;
51574 this.buttons[0].dialog = dlg;
51575 this.buttons[1].form = this.form;
51576 this.buttons[1].dialog = dlg;
51578 //this.resizeToLogo.defer(1000,this);
51579 // this is all related to resizing for logos..
51580 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
51582 // this.resizeToLogo.defer(1000,this);
51585 //var w = Ext.lib.Dom.getViewWidth() - 100;
51586 //var h = Ext.lib.Dom.getViewHeight() - 100;
51587 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
51589 if (this.disabled) {
51594 if (this.user.id < 0) { // used for inital setup situations.
51598 if (this.intervalID) {
51599 // remove the timer
51600 window.clearInterval(this.intervalID);
51601 this.intervalID = false;
51605 if (Roo.get('loading')) {
51606 Roo.get('loading').remove();
51608 if (Roo.get('loading-mask')) {
51609 Roo.get('loading-mask').hide();
51612 //incomming._node = tnode;
51614 //this.dialog.modal = !modal;
51615 //this.dialog.show();
51619 this.form.setValues({
51620 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
51621 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
51624 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
51625 if (this.form.findField('username').getValue().length > 0 ){
51626 this.form.findField('password').focus();
51628 this.form.findField('username').focus();
51636 xtype : 'ContentPanel',
51648 style : 'margin: 10px;',
51651 actionfailed : function(f, act) {
51652 // form can return { errors: .... }
51654 //act.result.errors // invalid form element list...
51655 //act.result.errorMsg// invalid form element list...
51657 this.dialog.el.unmask();
51658 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
51659 "Login failed - communication error - try again.");
51662 actioncomplete: function(re, act) {
51664 Roo.state.Manager.set(
51665 this.dialog.realm + '.username',
51666 this.findField('username').getValue()
51668 Roo.state.Manager.set(
51669 this.dialog.realm + '.lang',
51670 this.findField('lang').getValue()
51673 this.dialog.fillAuth(act.result.data);
51675 this.dialog.hide();
51677 if (Roo.get('loading-mask')) {
51678 Roo.get('loading-mask').show();
51680 Roo.XComponent.build();
51688 xtype : 'TextField',
51690 fieldLabel: "Email Address",
51693 autoCreate : {tag: "input", type: "text", size: "20"}
51696 xtype : 'TextField',
51698 fieldLabel: "Password",
51699 inputType: 'password',
51702 autoCreate : {tag: "input", type: "text", size: "20"},
51704 specialkey : function(e,ev) {
51705 if (ev.keyCode == 13) {
51706 this.form.dialog.el.mask("Logging in");
51707 this.form.doAction('submit', {
51708 url: this.form.dialog.url,
51709 method: this.form.dialog.method
51716 xtype : 'ComboBox',
51718 fieldLabel: "Language",
51721 xtype : 'SimpleStore',
51722 fields: ['lang', 'ldisp'],
51724 [ 'en', 'English' ],
51725 [ 'zh_HK' , '\u7E41\u4E2D' ],
51726 [ 'zh_CN', '\u7C21\u4E2D' ]
51730 valueField : 'lang',
51731 hiddenName: 'lang',
51733 displayField:'ldisp',
51737 triggerAction: 'all',
51738 emptyText:'Select a Language...',
51739 selectOnFocus:true,
51741 select : function(cb, rec, ix) {
51742 this.form.switchLang(rec.data.lang);
51758 text : "Forgot Password",
51760 click : function() {
51761 //console.log(this);
51762 var n = this.form.findField('username').getValue();
51764 Roo.MessageBox.alert("Error", "Fill in your email address");
51768 url: this.dialog.url,
51772 method: this.dialog.method,
51773 success: function(response, opts) { // check successfull...
51775 var res = this.dialog.processResponse(response);
51776 if (!res.success) { // error!
51777 Roo.MessageBox.alert("Error" ,
51778 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
51781 Roo.MessageBox.alert("Notice" ,
51782 "Please check you email for the Password Reset message");
51784 failure : function() {
51785 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
51798 click : function () {
51800 this.dialog.el.mask("Logging in");
51801 this.form.doAction('submit', {
51802 url: this.dialog.url,
51803 method: this.dialog.method