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) : new Roo.Element(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){
7825 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7830 * Removes an event handler from this element
7831 * @param {String} eventName the type of event to remove
7832 * @param {Function} fn the method the event invokes
7833 * @return {Roo.Element} this
7835 removeListener : function(eventName, fn){
7836 Roo.EventManager.removeListener(this.dom, eventName, fn);
7841 * Removes all previous added listeners from this element
7842 * @return {Roo.Element} this
7844 removeAllListeners : function(){
7845 E.purgeElement(this.dom);
7849 relayEvent : function(eventName, observable){
7850 this.on(eventName, function(e){
7851 observable.fireEvent(eventName, e);
7856 * Set the opacity of the element
7857 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7858 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7859 * @return {Roo.Element} this
7861 setOpacity : function(opacity, animate){
7863 var s = this.dom.style;
7866 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7867 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7869 s.opacity = opacity;
7872 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7878 * Gets the left X coordinate
7879 * @param {Boolean} local True to get the local css position instead of page coordinate
7882 getLeft : function(local){
7886 return parseInt(this.getStyle("left"), 10) || 0;
7891 * Gets the right X coordinate of the element (element X position + element width)
7892 * @param {Boolean} local True to get the local css position instead of page coordinate
7895 getRight : function(local){
7897 return this.getX() + this.getWidth();
7899 return (this.getLeft(true) + this.getWidth()) || 0;
7904 * Gets the top Y coordinate
7905 * @param {Boolean} local True to get the local css position instead of page coordinate
7908 getTop : function(local) {
7912 return parseInt(this.getStyle("top"), 10) || 0;
7917 * Gets the bottom Y coordinate of the element (element Y position + element height)
7918 * @param {Boolean} local True to get the local css position instead of page coordinate
7921 getBottom : function(local){
7923 return this.getY() + this.getHeight();
7925 return (this.getTop(true) + this.getHeight()) || 0;
7930 * Initializes positioning on this element. If a desired position is not passed, it will make the
7931 * the element positioned relative IF it is not already positioned.
7932 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7933 * @param {Number} zIndex (optional) The zIndex to apply
7934 * @param {Number} x (optional) Set the page X position
7935 * @param {Number} y (optional) Set the page Y position
7937 position : function(pos, zIndex, x, y){
7939 if(this.getStyle('position') == 'static'){
7940 this.setStyle('position', 'relative');
7943 this.setStyle("position", pos);
7946 this.setStyle("z-index", zIndex);
7948 if(x !== undefined && y !== undefined){
7950 }else if(x !== undefined){
7952 }else if(y !== undefined){
7958 * Clear positioning back to the default when the document was loaded
7959 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7960 * @return {Roo.Element} this
7962 clearPositioning : function(value){
7970 "position" : "static"
7976 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7977 * snapshot before performing an update and then restoring the element.
7980 getPositioning : function(){
7981 var l = this.getStyle("left");
7982 var t = this.getStyle("top");
7984 "position" : this.getStyle("position"),
7986 "right" : l ? "" : this.getStyle("right"),
7988 "bottom" : t ? "" : this.getStyle("bottom"),
7989 "z-index" : this.getStyle("z-index")
7994 * Gets the width of the border(s) for the specified side(s)
7995 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7996 * passing lr would get the border (l)eft width + the border (r)ight width.
7997 * @return {Number} The width of the sides passed added together
7999 getBorderWidth : function(side){
8000 return this.addStyles(side, El.borders);
8004 * Gets the width of the padding(s) for the specified side(s)
8005 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8006 * passing lr would get the padding (l)eft + the padding (r)ight.
8007 * @return {Number} The padding of the sides passed added together
8009 getPadding : function(side){
8010 return this.addStyles(side, El.paddings);
8014 * Set positioning with an object returned by getPositioning().
8015 * @param {Object} posCfg
8016 * @return {Roo.Element} this
8018 setPositioning : function(pc){
8019 this.applyStyles(pc);
8020 if(pc.right == "auto"){
8021 this.dom.style.right = "";
8023 if(pc.bottom == "auto"){
8024 this.dom.style.bottom = "";
8030 fixDisplay : function(){
8031 if(this.getStyle("display") == "none"){
8032 this.setStyle("visibility", "hidden");
8033 this.setStyle("display", this.originalDisplay); // first try reverting to default
8034 if(this.getStyle("display") == "none"){ // if that fails, default to block
8035 this.setStyle("display", "block");
8041 * Quick set left and top adding default units
8042 * @param {String} left The left CSS property value
8043 * @param {String} top The top CSS property value
8044 * @return {Roo.Element} this
8046 setLeftTop : function(left, top){
8047 this.dom.style.left = this.addUnits(left);
8048 this.dom.style.top = this.addUnits(top);
8053 * Move this element relative to its current position.
8054 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8055 * @param {Number} distance How far to move the element in pixels
8056 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8057 * @return {Roo.Element} this
8059 move : function(direction, distance, animate){
8060 var xy = this.getXY();
8061 direction = direction.toLowerCase();
8065 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8069 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8074 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8079 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8086 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8087 * @return {Roo.Element} this
8090 if(!this.isClipped){
8091 this.isClipped = true;
8092 this.originalClip = {
8093 "o": this.getStyle("overflow"),
8094 "x": this.getStyle("overflow-x"),
8095 "y": this.getStyle("overflow-y")
8097 this.setStyle("overflow", "hidden");
8098 this.setStyle("overflow-x", "hidden");
8099 this.setStyle("overflow-y", "hidden");
8105 * Return clipping (overflow) to original clipping before clip() was called
8106 * @return {Roo.Element} this
8108 unclip : function(){
8110 this.isClipped = false;
8111 var o = this.originalClip;
8112 if(o.o){this.setStyle("overflow", o.o);}
8113 if(o.x){this.setStyle("overflow-x", o.x);}
8114 if(o.y){this.setStyle("overflow-y", o.y);}
8121 * Gets the x,y coordinates specified by the anchor position on the element.
8122 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8123 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8124 * {width: (target width), height: (target height)} (defaults to the element's current size)
8125 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8126 * @return {Array} [x, y] An array containing the element's x and y coordinates
8128 getAnchorXY : function(anchor, local, s){
8129 //Passing a different size is useful for pre-calculating anchors,
8130 //especially for anchored animations that change the el size.
8132 var w, h, vp = false;
8135 if(d == document.body || d == document){
8137 w = D.getViewWidth(); h = D.getViewHeight();
8139 w = this.getWidth(); h = this.getHeight();
8142 w = s.width; h = s.height;
8144 var x = 0, y = 0, r = Math.round;
8145 switch((anchor || "tl").toLowerCase()){
8187 var sc = this.getScroll();
8188 return [x + sc.left, y + sc.top];
8190 //Add the element's offset xy
8191 var o = this.getXY();
8192 return [x+o[0], y+o[1]];
8196 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8197 * supported position values.
8198 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8199 * @param {String} position The position to align to.
8200 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8201 * @return {Array} [x, y]
8203 getAlignToXY : function(el, p, o){
8207 throw "Element.alignTo with an element that doesn't exist";
8209 var c = false; //constrain to viewport
8210 var p1 = "", p2 = "";
8217 }else if(p.indexOf("-") == -1){
8220 p = p.toLowerCase();
8221 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8223 throw "Element.alignTo with an invalid alignment " + p;
8225 p1 = m[1]; p2 = m[2]; c = !!m[3];
8227 //Subtract the aligned el's internal xy from the target's offset xy
8228 //plus custom offset to get the aligned el's new offset xy
8229 var a1 = this.getAnchorXY(p1, true);
8230 var a2 = el.getAnchorXY(p2, false);
8231 var x = a2[0] - a1[0] + o[0];
8232 var y = a2[1] - a1[1] + o[1];
8234 //constrain the aligned el to viewport if necessary
8235 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8236 // 5px of margin for ie
8237 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8239 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8240 //perpendicular to the vp border, allow the aligned el to slide on that border,
8241 //otherwise swap the aligned el to the opposite border of the target.
8242 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8243 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8244 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8245 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8248 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8249 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8251 if((x+w) > dw + scrollX){
8252 x = swapX ? r.left-w : dw+scrollX-w;
8255 x = swapX ? r.right : scrollX;
8257 if((y+h) > dh + scrollY){
8258 y = swapY ? r.top-h : dh+scrollY-h;
8261 y = swapY ? r.bottom : scrollY;
8268 getConstrainToXY : function(){
8269 var os = {top:0, left:0, bottom:0, right: 0};
8271 return function(el, local, offsets, proposedXY){
8273 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8275 var vw, vh, vx = 0, vy = 0;
8276 if(el.dom == document.body || el.dom == document){
8277 vw = Roo.lib.Dom.getViewWidth();
8278 vh = Roo.lib.Dom.getViewHeight();
8280 vw = el.dom.clientWidth;
8281 vh = el.dom.clientHeight;
8283 var vxy = el.getXY();
8289 var s = el.getScroll();
8291 vx += offsets.left + s.left;
8292 vy += offsets.top + s.top;
8294 vw -= offsets.right;
8295 vh -= offsets.bottom;
8300 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8301 var x = xy[0], y = xy[1];
8302 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8304 // only move it if it needs it
8307 // first validate right/bottom
8316 // then make sure top/left isn't negative
8325 return moved ? [x, y] : false;
8330 adjustForConstraints : function(xy, parent, offsets){
8331 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8335 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8336 * document it aligns it to the viewport.
8337 * The position parameter is optional, and can be specified in any one of the following formats:
8339 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8340 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8341 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8342 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8343 * <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
8344 * element's anchor point, and the second value is used as the target's anchor point.</li>
8346 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8347 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8348 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8349 * that specified in order to enforce the viewport constraints.
8350 * Following are all of the supported anchor positions:
8353 ----- -----------------------------
8354 tl The top left corner (default)
8355 t The center of the top edge
8356 tr The top right corner
8357 l The center of the left edge
8358 c In the center of the element
8359 r The center of the right edge
8360 bl The bottom left corner
8361 b The center of the bottom edge
8362 br The bottom right corner
8366 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8367 el.alignTo("other-el");
8369 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8370 el.alignTo("other-el", "tr?");
8372 // align the bottom right corner of el with the center left edge of other-el
8373 el.alignTo("other-el", "br-l?");
8375 // align the center of el with the bottom left corner of other-el and
8376 // adjust the x position by -6 pixels (and the y position by 0)
8377 el.alignTo("other-el", "c-bl", [-6, 0]);
8379 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8380 * @param {String} position The position to align to.
8381 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8382 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8383 * @return {Roo.Element} this
8385 alignTo : function(element, position, offsets, animate){
8386 var xy = this.getAlignToXY(element, position, offsets);
8387 this.setXY(xy, this.preanim(arguments, 3));
8392 * Anchors an element to another element and realigns it when the window is resized.
8393 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8394 * @param {String} position The position to align to.
8395 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8396 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8397 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8398 * is a number, it is used as the buffer delay (defaults to 50ms).
8399 * @param {Function} callback The function to call after the animation finishes
8400 * @return {Roo.Element} this
8402 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8403 var action = function(){
8404 this.alignTo(el, alignment, offsets, animate);
8405 Roo.callback(callback, this);
8407 Roo.EventManager.onWindowResize(action, this);
8408 var tm = typeof monitorScroll;
8409 if(tm != 'undefined'){
8410 Roo.EventManager.on(window, 'scroll', action, this,
8411 {buffer: tm == 'number' ? monitorScroll : 50});
8413 action.call(this); // align immediately
8417 * Clears any opacity settings from this element. Required in some cases for IE.
8418 * @return {Roo.Element} this
8420 clearOpacity : function(){
8421 if (window.ActiveXObject) {
8422 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8423 this.dom.style.filter = "";
8426 this.dom.style.opacity = "";
8427 this.dom.style["-moz-opacity"] = "";
8428 this.dom.style["-khtml-opacity"] = "";
8434 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8435 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8436 * @return {Roo.Element} this
8438 hide : function(animate){
8439 this.setVisible(false, this.preanim(arguments, 0));
8444 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8445 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8446 * @return {Roo.Element} this
8448 show : function(animate){
8449 this.setVisible(true, this.preanim(arguments, 0));
8454 * @private Test if size has a unit, otherwise appends the default
8456 addUnits : function(size){
8457 return Roo.Element.addUnits(size, this.defaultUnit);
8461 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8462 * @return {Roo.Element} this
8464 beginMeasure : function(){
8466 if(el.offsetWidth || el.offsetHeight){
8467 return this; // offsets work already
8470 var p = this.dom, b = document.body; // start with this element
8471 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8472 var pe = Roo.get(p);
8473 if(pe.getStyle('display') == 'none'){
8474 changed.push({el: p, visibility: pe.getStyle("visibility")});
8475 p.style.visibility = "hidden";
8476 p.style.display = "block";
8480 this._measureChanged = changed;
8486 * Restores displays to before beginMeasure was called
8487 * @return {Roo.Element} this
8489 endMeasure : function(){
8490 var changed = this._measureChanged;
8492 for(var i = 0, len = changed.length; i < len; i++) {
8494 r.el.style.visibility = r.visibility;
8495 r.el.style.display = "none";
8497 this._measureChanged = null;
8503 * Update the innerHTML of this element, optionally searching for and processing scripts
8504 * @param {String} html The new HTML
8505 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8506 * @param {Function} callback For async script loading you can be noticed when the update completes
8507 * @return {Roo.Element} this
8509 update : function(html, loadScripts, callback){
8510 if(typeof html == "undefined"){
8513 if(loadScripts !== true){
8514 this.dom.innerHTML = html;
8515 if(typeof callback == "function"){
8523 html += '<span id="' + id + '"></span>';
8525 E.onAvailable(id, function(){
8526 var hd = document.getElementsByTagName("head")[0];
8527 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8528 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8529 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8532 while(match = re.exec(html)){
8533 var attrs = match[1];
8534 var srcMatch = attrs ? attrs.match(srcRe) : false;
8535 if(srcMatch && srcMatch[2]){
8536 var s = document.createElement("script");
8537 s.src = srcMatch[2];
8538 var typeMatch = attrs.match(typeRe);
8539 if(typeMatch && typeMatch[2]){
8540 s.type = typeMatch[2];
8543 }else if(match[2] && match[2].length > 0){
8544 if(window.execScript) {
8545 window.execScript(match[2]);
8553 window.eval(match[2]);
8557 var el = document.getElementById(id);
8558 if(el){el.parentNode.removeChild(el);}
8559 if(typeof callback == "function"){
8563 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8568 * Direct access to the UpdateManager update() method (takes the same parameters).
8569 * @param {String/Function} url The url for this request or a function to call to get the url
8570 * @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}
8571 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8572 * @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.
8573 * @return {Roo.Element} this
8576 var um = this.getUpdateManager();
8577 um.update.apply(um, arguments);
8582 * Gets this element's UpdateManager
8583 * @return {Roo.UpdateManager} The UpdateManager
8585 getUpdateManager : function(){
8586 if(!this.updateManager){
8587 this.updateManager = new Roo.UpdateManager(this);
8589 return this.updateManager;
8593 * Disables text selection for this element (normalized across browsers)
8594 * @return {Roo.Element} this
8596 unselectable : function(){
8597 this.dom.unselectable = "on";
8598 this.swallowEvent("selectstart", true);
8599 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8600 this.addClass("x-unselectable");
8605 * Calculates the x, y to center this element on the screen
8606 * @return {Array} The x, y values [x, y]
8608 getCenterXY : function(){
8609 return this.getAlignToXY(document, 'c-c');
8613 * Centers the Element in either the viewport, or another Element.
8614 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8616 center : function(centerIn){
8617 this.alignTo(centerIn || document, 'c-c');
8622 * Tests various css rules/browsers to determine if this element uses a border box
8625 isBorderBox : function(){
8626 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8630 * Return a box {x, y, width, height} that can be used to set another elements
8631 * size/location to match this element.
8632 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8633 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8634 * @return {Object} box An object in the format {x, y, width, height}
8636 getBox : function(contentBox, local){
8641 var left = parseInt(this.getStyle("left"), 10) || 0;
8642 var top = parseInt(this.getStyle("top"), 10) || 0;
8645 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8647 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8649 var l = this.getBorderWidth("l")+this.getPadding("l");
8650 var r = this.getBorderWidth("r")+this.getPadding("r");
8651 var t = this.getBorderWidth("t")+this.getPadding("t");
8652 var b = this.getBorderWidth("b")+this.getPadding("b");
8653 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)};
8655 bx.right = bx.x + bx.width;
8656 bx.bottom = bx.y + bx.height;
8661 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8662 for more information about the sides.
8663 * @param {String} sides
8666 getFrameWidth : function(sides, onlyContentBox){
8667 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8671 * 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.
8672 * @param {Object} box The box to fill {x, y, width, height}
8673 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8674 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8675 * @return {Roo.Element} this
8677 setBox : function(box, adjust, animate){
8678 var w = box.width, h = box.height;
8679 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8680 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8681 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8683 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8688 * Forces the browser to repaint this element
8689 * @return {Roo.Element} this
8691 repaint : function(){
8693 this.addClass("x-repaint");
8694 setTimeout(function(){
8695 Roo.get(dom).removeClass("x-repaint");
8701 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8702 * then it returns the calculated width of the sides (see getPadding)
8703 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8704 * @return {Object/Number}
8706 getMargins : function(side){
8709 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8710 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8711 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8712 right: parseInt(this.getStyle("margin-right"), 10) || 0
8715 return this.addStyles(side, El.margins);
8720 addStyles : function(sides, styles){
8722 for(var i = 0, len = sides.length; i < len; i++){
8723 v = this.getStyle(styles[sides.charAt(i)]);
8725 w = parseInt(v, 10);
8733 * Creates a proxy element of this element
8734 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8735 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8736 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8737 * @return {Roo.Element} The new proxy element
8739 createProxy : function(config, renderTo, matchBox){
8741 renderTo = Roo.getDom(renderTo);
8743 renderTo = document.body;
8745 config = typeof config == "object" ?
8746 config : {tag : "div", cls: config};
8747 var proxy = Roo.DomHelper.append(renderTo, config, true);
8749 proxy.setBox(this.getBox());
8755 * Puts a mask over this element to disable user interaction. Requires core.css.
8756 * This method can only be applied to elements which accept child nodes.
8757 * @param {String} msg (optional) A message to display in the mask
8758 * @param {String} msgCls (optional) A css class to apply to the msg element
8759 * @return {Element} The mask element
8761 mask : function(msg, msgCls){
8762 if(this.getStyle("position") == "static"){
8763 this.setStyle("position", "relative");
8766 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8768 this.addClass("x-masked");
8769 this._mask.setDisplayed(true);
8770 if(typeof msg == 'string'){
8772 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8774 var mm = this._maskMsg;
8775 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8776 mm.dom.firstChild.innerHTML = msg;
8777 mm.setDisplayed(true);
8780 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8781 this._mask.setHeight(this.getHeight());
8787 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8788 * it is cached for reuse.
8790 unmask : function(removeEl){
8792 if(removeEl === true){
8793 this._mask.remove();
8796 this._maskMsg.remove();
8797 delete this._maskMsg;
8800 this._mask.setDisplayed(false);
8802 this._maskMsg.setDisplayed(false);
8806 this.removeClass("x-masked");
8810 * Returns true if this element is masked
8813 isMasked : function(){
8814 return this._mask && this._mask.isVisible();
8818 * Creates an iframe shim for this element to keep selects and other windowed objects from
8820 * @return {Roo.Element} The new shim element
8822 createShim : function(){
8823 var el = document.createElement('iframe');
8824 el.frameBorder = 'no';
8825 el.className = 'roo-shim';
8826 if(Roo.isIE && Roo.isSecure){
8827 el.src = Roo.SSL_SECURE_URL;
8829 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8830 shim.autoBoxAdjust = false;
8835 * Removes this element from the DOM and deletes it from the cache
8837 remove : function(){
8838 if(this.dom.parentNode){
8839 this.dom.parentNode.removeChild(this.dom);
8841 delete El.cache[this.dom.id];
8845 * Sets up event handlers to add and remove a css class when the mouse is over this element
8846 * @param {String} className
8847 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8848 * mouseout events for children elements
8849 * @return {Roo.Element} this
8851 addClassOnOver : function(className, preventFlicker){
8852 this.on("mouseover", function(){
8853 Roo.fly(this, '_internal').addClass(className);
8855 var removeFn = function(e){
8856 if(preventFlicker !== true || !e.within(this, true)){
8857 Roo.fly(this, '_internal').removeClass(className);
8860 this.on("mouseout", removeFn, this.dom);
8865 * Sets up event handlers to add and remove a css class when this element has the focus
8866 * @param {String} className
8867 * @return {Roo.Element} this
8869 addClassOnFocus : function(className){
8870 this.on("focus", function(){
8871 Roo.fly(this, '_internal').addClass(className);
8873 this.on("blur", function(){
8874 Roo.fly(this, '_internal').removeClass(className);
8879 * 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)
8880 * @param {String} className
8881 * @return {Roo.Element} this
8883 addClassOnClick : function(className){
8885 this.on("mousedown", function(){
8886 Roo.fly(dom, '_internal').addClass(className);
8887 var d = Roo.get(document);
8888 var fn = function(){
8889 Roo.fly(dom, '_internal').removeClass(className);
8890 d.removeListener("mouseup", fn);
8892 d.on("mouseup", fn);
8898 * Stops the specified event from bubbling and optionally prevents the default action
8899 * @param {String} eventName
8900 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8901 * @return {Roo.Element} this
8903 swallowEvent : function(eventName, preventDefault){
8904 var fn = function(e){
8905 e.stopPropagation();
8910 if(eventName instanceof Array){
8911 for(var i = 0, len = eventName.length; i < len; i++){
8912 this.on(eventName[i], fn);
8916 this.on(eventName, fn);
8923 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8926 * Sizes this element to its parent element's dimensions performing
8927 * neccessary box adjustments.
8928 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8929 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8930 * @return {Roo.Element} this
8932 fitToParent : function(monitorResize, targetParent) {
8933 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8934 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8935 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8938 var p = Roo.get(targetParent || this.dom.parentNode);
8939 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8940 if (monitorResize === true) {
8941 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8942 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8948 * Gets the next sibling, skipping text nodes
8949 * @return {HTMLElement} The next sibling or null
8951 getNextSibling : function(){
8952 var n = this.dom.nextSibling;
8953 while(n && n.nodeType != 1){
8960 * Gets the previous sibling, skipping text nodes
8961 * @return {HTMLElement} The previous sibling or null
8963 getPrevSibling : function(){
8964 var n = this.dom.previousSibling;
8965 while(n && n.nodeType != 1){
8966 n = n.previousSibling;
8973 * Appends the passed element(s) to this element
8974 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8975 * @return {Roo.Element} this
8977 appendChild: function(el){
8984 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8985 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8986 * automatically generated with the specified attributes.
8987 * @param {HTMLElement} insertBefore (optional) a child element of this element
8988 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8989 * @return {Roo.Element} The new child element
8991 createChild: function(config, insertBefore, returnDom){
8992 config = config || {tag:'div'};
8994 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8996 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9000 * Appends this element to the passed element
9001 * @param {String/HTMLElement/Element} el The new parent element
9002 * @return {Roo.Element} this
9004 appendTo: function(el){
9005 el = Roo.getDom(el);
9006 el.appendChild(this.dom);
9011 * Inserts this element before the passed element in the DOM
9012 * @param {String/HTMLElement/Element} el The element to insert before
9013 * @return {Roo.Element} this
9015 insertBefore: function(el){
9016 el = Roo.getDom(el);
9017 el.parentNode.insertBefore(this.dom, el);
9022 * Inserts this element after the passed element in the DOM
9023 * @param {String/HTMLElement/Element} el The element to insert after
9024 * @return {Roo.Element} this
9026 insertAfter: function(el){
9027 el = Roo.getDom(el);
9028 el.parentNode.insertBefore(this.dom, el.nextSibling);
9033 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9034 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9035 * @return {Roo.Element} The new child
9037 insertFirst: function(el, returnDom){
9039 if(typeof el == 'object' && !el.nodeType){ // dh config
9040 return this.createChild(el, this.dom.firstChild, returnDom);
9042 el = Roo.getDom(el);
9043 this.dom.insertBefore(el, this.dom.firstChild);
9044 return !returnDom ? Roo.get(el) : el;
9049 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9050 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9051 * @param {String} where (optional) 'before' or 'after' defaults to before
9052 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9053 * @return {Roo.Element} the inserted Element
9055 insertSibling: function(el, where, returnDom){
9056 where = where ? where.toLowerCase() : 'before';
9058 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9060 if(typeof el == 'object' && !el.nodeType){ // dh config
9061 if(where == 'after' && !this.dom.nextSibling){
9062 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9064 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9068 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9069 where == 'before' ? this.dom : this.dom.nextSibling);
9078 * Creates and wraps this element with another element
9079 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9080 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9081 * @return {HTMLElement/Element} The newly created wrapper element
9083 wrap: function(config, returnDom){
9085 config = {tag: "div"};
9087 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9088 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9093 * Replaces the passed element with this element
9094 * @param {String/HTMLElement/Element} el The element to replace
9095 * @return {Roo.Element} this
9097 replace: function(el){
9099 this.insertBefore(el);
9105 * Inserts an html fragment into this element
9106 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9107 * @param {String} html The HTML fragment
9108 * @param {Boolean} returnEl True to return an Roo.Element
9109 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9111 insertHtml : function(where, html, returnEl){
9112 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9113 return returnEl ? Roo.get(el) : el;
9117 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9118 * @param {Object} o The object with the attributes
9119 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9120 * @return {Roo.Element} this
9122 set : function(o, useSet){
9124 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9126 if(attr == "style" || typeof o[attr] == "function") continue;
9128 el.className = o["cls"];
9130 if(useSet) el.setAttribute(attr, o[attr]);
9131 else el[attr] = o[attr];
9135 Roo.DomHelper.applyStyles(el, o.style);
9141 * Convenience method for constructing a KeyMap
9142 * @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:
9143 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9144 * @param {Function} fn The function to call
9145 * @param {Object} scope (optional) The scope of the function
9146 * @return {Roo.KeyMap} The KeyMap created
9148 addKeyListener : function(key, fn, scope){
9150 if(typeof key != "object" || key instanceof Array){
9166 return new Roo.KeyMap(this, config);
9170 * Creates a KeyMap for this element
9171 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9172 * @return {Roo.KeyMap} The KeyMap created
9174 addKeyMap : function(config){
9175 return new Roo.KeyMap(this, config);
9179 * Returns true if this element is scrollable.
9182 isScrollable : function(){
9184 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9188 * 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().
9189 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9190 * @param {Number} value The new scroll value
9191 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9192 * @return {Element} this
9195 scrollTo : function(side, value, animate){
9196 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9198 this.dom[prop] = value;
9200 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9201 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9207 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9208 * within this element's scrollable range.
9209 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9210 * @param {Number} distance How far to scroll the element in pixels
9211 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9212 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9213 * was scrolled as far as it could go.
9215 scroll : function(direction, distance, animate){
9216 if(!this.isScrollable()){
9220 var l = el.scrollLeft, t = el.scrollTop;
9221 var w = el.scrollWidth, h = el.scrollHeight;
9222 var cw = el.clientWidth, ch = el.clientHeight;
9223 direction = direction.toLowerCase();
9224 var scrolled = false;
9225 var a = this.preanim(arguments, 2);
9230 var v = Math.min(l + distance, w-cw);
9231 this.scrollTo("left", v, a);
9238 var v = Math.max(l - distance, 0);
9239 this.scrollTo("left", v, a);
9247 var v = Math.max(t - distance, 0);
9248 this.scrollTo("top", v, a);
9256 var v = Math.min(t + distance, h-ch);
9257 this.scrollTo("top", v, a);
9266 * Translates the passed page coordinates into left/top css values for this element
9267 * @param {Number/Array} x The page x or an array containing [x, y]
9268 * @param {Number} y The page y
9269 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9271 translatePoints : function(x, y){
9272 if(typeof x == 'object' || x instanceof Array){
9275 var p = this.getStyle('position');
9276 var o = this.getXY();
9278 var l = parseInt(this.getStyle('left'), 10);
9279 var t = parseInt(this.getStyle('top'), 10);
9282 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9285 t = (p == "relative") ? 0 : this.dom.offsetTop;
9288 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9292 * Returns the current scroll position of the element.
9293 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9295 getScroll : function(){
9296 var d = this.dom, doc = document;
9297 if(d == doc || d == doc.body){
9298 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9299 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9300 return {left: l, top: t};
9302 return {left: d.scrollLeft, top: d.scrollTop};
9307 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9308 * are convert to standard 6 digit hex color.
9309 * @param {String} attr The css attribute
9310 * @param {String} defaultValue The default value to use when a valid color isn't found
9311 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9314 getColor : function(attr, defaultValue, prefix){
9315 var v = this.getStyle(attr);
9316 if(!v || v == "transparent" || v == "inherit") {
9317 return defaultValue;
9319 var color = typeof prefix == "undefined" ? "#" : prefix;
9320 if(v.substr(0, 4) == "rgb("){
9321 var rvs = v.slice(4, v.length -1).split(",");
9322 for(var i = 0; i < 3; i++){
9323 var h = parseInt(rvs[i]).toString(16);
9330 if(v.substr(0, 1) == "#"){
9332 for(var i = 1; i < 4; i++){
9333 var c = v.charAt(i);
9336 }else if(v.length == 7){
9337 color += v.substr(1);
9341 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9345 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9346 * gradient background, rounded corners and a 4-way shadow.
9347 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9348 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9349 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9350 * @return {Roo.Element} this
9352 boxWrap : function(cls){
9353 cls = cls || 'x-box';
9354 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9355 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9360 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9361 * @param {String} namespace The namespace in which to look for the attribute
9362 * @param {String} name The attribute name
9363 * @return {String} The attribute value
9365 getAttributeNS : Roo.isIE ? function(ns, name){
9367 var type = typeof d[ns+":"+name];
9368 if(type != 'undefined' && type != 'unknown'){
9369 return d[ns+":"+name];
9372 } : function(ns, name){
9374 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9378 var ep = El.prototype;
9381 * Appends an event handler (Shorthand for addListener)
9382 * @param {String} eventName The type of event to append
9383 * @param {Function} fn The method the event invokes
9384 * @param {Object} scope (optional) The scope (this object) of the fn
9385 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9388 ep.on = ep.addListener;
9390 ep.mon = ep.addListener;
9393 * Removes an event handler from this element (shorthand for removeListener)
9394 * @param {String} eventName the type of event to remove
9395 * @param {Function} fn the method the event invokes
9396 * @return {Roo.Element} this
9399 ep.un = ep.removeListener;
9402 * true to automatically adjust width and height settings for box-model issues (default to true)
9404 ep.autoBoxAdjust = true;
9407 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9410 El.addUnits = function(v, defaultUnit){
9411 if(v === "" || v == "auto"){
9414 if(v === undefined){
9417 if(typeof v == "number" || !El.unitPattern.test(v)){
9418 return v + (defaultUnit || 'px');
9423 // special markup used throughout Roo when box wrapping elements
9424 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>';
9426 * Visibility mode constant - Use visibility to hide element
9432 * Visibility mode constant - Use display to hide element
9438 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9439 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9440 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9452 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9453 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9454 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9455 * @return {Element} The Element object
9458 El.get = function(el){
9460 if(!el){ return null; }
9461 if(typeof el == "string"){ // element id
9462 if(!(elm = document.getElementById(el))){
9465 if(ex = El.cache[el]){
9468 ex = El.cache[el] = new El(elm);
9471 }else if(el.tagName){ // dom element
9475 if(ex = El.cache[id]){
9478 ex = El.cache[id] = new El(el);
9481 }else if(el instanceof El){
9483 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9484 // catch case where it hasn't been appended
9485 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9488 }else if(el.isComposite){
9490 }else if(el instanceof Array){
9491 return El.select(el);
9492 }else if(el == document){
9493 // create a bogus element object representing the document object
9495 var f = function(){};
9496 f.prototype = El.prototype;
9498 docEl.dom = document;
9506 El.uncache = function(el){
9507 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9509 delete El.cache[a[i].id || a[i]];
9515 // Garbage collection - uncache elements/purge listeners on orphaned elements
9516 // so we don't hold a reference and cause the browser to retain them
9517 El.garbageCollect = function(){
9518 if(!Roo.enableGarbageCollector){
9519 clearInterval(El.collectorThread);
9522 for(var eid in El.cache){
9523 var el = El.cache[eid], d = el.dom;
9524 // -------------------------------------------------------
9525 // Determining what is garbage:
9526 // -------------------------------------------------------
9528 // dom node is null, definitely garbage
9529 // -------------------------------------------------------
9531 // no parentNode == direct orphan, definitely garbage
9532 // -------------------------------------------------------
9533 // !d.offsetParent && !document.getElementById(eid)
9534 // display none elements have no offsetParent so we will
9535 // also try to look it up by it's id. However, check
9536 // offsetParent first so we don't do unneeded lookups.
9537 // This enables collection of elements that are not orphans
9538 // directly, but somewhere up the line they have an orphan
9540 // -------------------------------------------------------
9541 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9542 delete El.cache[eid];
9543 if(d && Roo.enableListenerCollection){
9549 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9553 El.Flyweight = function(dom){
9556 El.Flyweight.prototype = El.prototype;
9558 El._flyweights = {};
9560 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9561 * the dom node can be overwritten by other code.
9562 * @param {String/HTMLElement} el The dom node or id
9563 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9564 * prevent conflicts (e.g. internally Roo uses "_internal")
9566 * @return {Element} The shared Element object
9568 El.fly = function(el, named){
9569 named = named || '_global';
9570 el = Roo.getDom(el);
9574 if(!El._flyweights[named]){
9575 El._flyweights[named] = new El.Flyweight();
9577 El._flyweights[named].dom = el;
9578 return El._flyweights[named];
9582 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9583 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9584 * Shorthand of {@link Roo.Element#get}
9585 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9586 * @return {Element} The Element object
9592 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9593 * the dom node can be overwritten by other code.
9594 * Shorthand of {@link Roo.Element#fly}
9595 * @param {String/HTMLElement} el The dom node or id
9596 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9597 * prevent conflicts (e.g. internally Roo uses "_internal")
9599 * @return {Element} The shared Element object
9605 // speedy lookup for elements never to box adjust
9606 var noBoxAdjust = Roo.isStrict ? {
9609 input:1, select:1, textarea:1
9611 if(Roo.isIE || Roo.isGecko){
9612 noBoxAdjust['button'] = 1;
9616 Roo.EventManager.on(window, 'unload', function(){
9618 delete El._flyweights;
9626 Roo.Element.selectorFunction = Roo.DomQuery.select;
9629 Roo.Element.select = function(selector, unique, root){
9631 if(typeof selector == "string"){
9632 els = Roo.Element.selectorFunction(selector, root);
9633 }else if(selector.length !== undefined){
9636 throw "Invalid selector";
9638 if(unique === true){
9639 return new Roo.CompositeElement(els);
9641 return new Roo.CompositeElementLite(els);
9645 * Selects elements based on the passed CSS selector to enable working on them as 1.
9646 * @param {String/Array} selector The CSS selector or an array of elements
9647 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9648 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9649 * @return {CompositeElementLite/CompositeElement}
9653 Roo.select = Roo.Element.select;
9670 * Ext JS Library 1.1.1
9671 * Copyright(c) 2006-2007, Ext JS, LLC.
9673 * Originally Released Under LGPL - original licence link has changed is not relivant.
9676 * <script type="text/javascript">
9681 //Notifies Element that fx methods are available
9682 Roo.enableFx = true;
9686 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9687 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9688 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9689 * Element effects to work.</p><br/>
9691 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9692 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9693 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9694 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9695 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9696 * expected results and should be done with care.</p><br/>
9698 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9699 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9702 ----- -----------------------------
9703 tl The top left corner
9704 t The center of the top edge
9705 tr The top right corner
9706 l The center of the left edge
9707 r The center of the right edge
9708 bl The bottom left corner
9709 b The center of the bottom edge
9710 br The bottom right corner
9712 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9713 * below are common options that can be passed to any Fx method.</b>
9714 * @cfg {Function} callback A function called when the effect is finished
9715 * @cfg {Object} scope The scope of the effect function
9716 * @cfg {String} easing A valid Easing value for the effect
9717 * @cfg {String} afterCls A css class to apply after the effect
9718 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9719 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9720 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9721 * effects that end with the element being visually hidden, ignored otherwise)
9722 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9723 * a function which returns such a specification that will be applied to the Element after the effect finishes
9724 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9725 * @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
9726 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9730 * Slides the element into view. An anchor point can be optionally passed to set the point of
9731 * origin for the slide effect. This function automatically handles wrapping the element with
9732 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9735 // default: slide the element in from the top
9738 // custom: slide the element in from the right with a 2-second duration
9739 el.slideIn('r', { duration: 2 });
9741 // common config options shown with default values
9747 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9748 * @param {Object} options (optional) Object literal with any of the Fx config options
9749 * @return {Roo.Element} The Element
9751 slideIn : function(anchor, o){
9752 var el = this.getFxEl();
9755 el.queueFx(o, function(){
9757 anchor = anchor || "t";
9759 // fix display to visibility
9762 // restore values after effect
9763 var r = this.getFxRestore();
9764 var b = this.getBox();
9765 // fixed size for slide
9769 var wrap = this.fxWrap(r.pos, o, "hidden");
9771 var st = this.dom.style;
9772 st.visibility = "visible";
9773 st.position = "absolute";
9775 // clear out temp styles after slide and unwrap
9776 var after = function(){
9777 el.fxUnwrap(wrap, r.pos, o);
9779 st.height = r.height;
9782 // time to calc the positions
9783 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9785 switch(anchor.toLowerCase()){
9787 wrap.setSize(b.width, 0);
9788 st.left = st.bottom = "0";
9792 wrap.setSize(0, b.height);
9793 st.right = st.top = "0";
9797 wrap.setSize(0, b.height);
9799 st.left = st.top = "0";
9800 a = {width: bw, points: pt};
9803 wrap.setSize(b.width, 0);
9804 wrap.setY(b.bottom);
9805 st.left = st.top = "0";
9806 a = {height: bh, points: pt};
9810 st.right = st.bottom = "0";
9811 a = {width: bw, height: bh};
9815 wrap.setY(b.y+b.height);
9816 st.right = st.top = "0";
9817 a = {width: bw, height: bh, points: pt};
9821 wrap.setXY([b.right, b.bottom]);
9822 st.left = st.top = "0";
9823 a = {width: bw, height: bh, points: pt};
9827 wrap.setX(b.x+b.width);
9828 st.left = st.bottom = "0";
9829 a = {width: bw, height: bh, points: pt};
9832 this.dom.style.visibility = "visible";
9835 arguments.callee.anim = wrap.fxanim(a,
9845 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9846 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9847 * 'hidden') but block elements will still take up space in the document. The element must be removed
9848 * from the DOM using the 'remove' config option if desired. This function automatically handles
9849 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9852 // default: slide the element out to the top
9855 // custom: slide the element out to the right with a 2-second duration
9856 el.slideOut('r', { duration: 2 });
9858 // common config options shown with default values
9866 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9867 * @param {Object} options (optional) Object literal with any of the Fx config options
9868 * @return {Roo.Element} The Element
9870 slideOut : function(anchor, o){
9871 var el = this.getFxEl();
9874 el.queueFx(o, function(){
9876 anchor = anchor || "t";
9878 // restore values after effect
9879 var r = this.getFxRestore();
9881 var b = this.getBox();
9882 // fixed size for slide
9886 var wrap = this.fxWrap(r.pos, o, "visible");
9888 var st = this.dom.style;
9889 st.visibility = "visible";
9890 st.position = "absolute";
9894 var after = function(){
9896 el.setDisplayed(false);
9901 el.fxUnwrap(wrap, r.pos, o);
9904 st.height = r.height;
9909 var a, zero = {to: 0};
9910 switch(anchor.toLowerCase()){
9912 st.left = st.bottom = "0";
9916 st.right = st.top = "0";
9920 st.left = st.top = "0";
9921 a = {width: zero, points: {to:[b.right, b.y]}};
9924 st.left = st.top = "0";
9925 a = {height: zero, points: {to:[b.x, b.bottom]}};
9928 st.right = st.bottom = "0";
9929 a = {width: zero, height: zero};
9932 st.right = st.top = "0";
9933 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9936 st.left = st.top = "0";
9937 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9940 st.left = st.bottom = "0";
9941 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9945 arguments.callee.anim = wrap.fxanim(a,
9955 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9956 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9957 * The element must be removed from the DOM using the 'remove' config option if desired.
9963 // common config options shown with default values
9971 * @param {Object} options (optional) Object literal with any of the Fx config options
9972 * @return {Roo.Element} The Element
9975 var el = this.getFxEl();
9978 el.queueFx(o, function(){
9979 this.clearOpacity();
9982 // restore values after effect
9983 var r = this.getFxRestore();
9984 var st = this.dom.style;
9986 var after = function(){
9988 el.setDisplayed(false);
9995 el.setPositioning(r.pos);
9997 st.height = r.height;
10002 var width = this.getWidth();
10003 var height = this.getHeight();
10005 arguments.callee.anim = this.fxanim({
10006 width : {to: this.adjustWidth(width * 2)},
10007 height : {to: this.adjustHeight(height * 2)},
10008 points : {by: [-(width * .5), -(height * .5)]},
10010 fontSize: {to:200, unit: "%"}
10021 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10022 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10023 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10029 // all config options shown with default values
10037 * @param {Object} options (optional) Object literal with any of the Fx config options
10038 * @return {Roo.Element} The Element
10040 switchOff : function(o){
10041 var el = this.getFxEl();
10044 el.queueFx(o, function(){
10045 this.clearOpacity();
10048 // restore values after effect
10049 var r = this.getFxRestore();
10050 var st = this.dom.style;
10052 var after = function(){
10054 el.setDisplayed(false);
10060 el.setPositioning(r.pos);
10061 st.width = r.width;
10062 st.height = r.height;
10067 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10068 this.clearOpacity();
10072 points:{by:[0, this.getHeight() * .5]}
10073 }, o, 'motion', 0.3, 'easeIn', after);
10074 }).defer(100, this);
10081 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10082 * changed using the "attr" config option) and then fading back to the original color. If no original
10083 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10086 // default: highlight background to yellow
10089 // custom: highlight foreground text to blue for 2 seconds
10090 el.highlight("0000ff", { attr: 'color', duration: 2 });
10092 // common config options shown with default values
10093 el.highlight("ffff9c", {
10094 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10095 endColor: (current color) or "ffffff",
10100 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10101 * @param {Object} options (optional) Object literal with any of the Fx config options
10102 * @return {Roo.Element} The Element
10104 highlight : function(color, o){
10105 var el = this.getFxEl();
10108 el.queueFx(o, function(){
10109 color = color || "ffff9c";
10110 attr = o.attr || "backgroundColor";
10112 this.clearOpacity();
10115 var origColor = this.getColor(attr);
10116 var restoreColor = this.dom.style[attr];
10117 endColor = (o.endColor || origColor) || "ffffff";
10119 var after = function(){
10120 el.dom.style[attr] = restoreColor;
10125 a[attr] = {from: color, to: endColor};
10126 arguments.callee.anim = this.fxanim(a,
10136 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10139 // default: a single light blue ripple
10142 // custom: 3 red ripples lasting 3 seconds total
10143 el.frame("ff0000", 3, { duration: 3 });
10145 // common config options shown with default values
10146 el.frame("C3DAF9", 1, {
10147 duration: 1 //duration of entire animation (not each individual ripple)
10148 // Note: Easing is not configurable and will be ignored if included
10151 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10152 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10153 * @param {Object} options (optional) Object literal with any of the Fx config options
10154 * @return {Roo.Element} The Element
10156 frame : function(color, count, o){
10157 var el = this.getFxEl();
10160 el.queueFx(o, function(){
10161 color = color || "#C3DAF9";
10162 if(color.length == 6){
10163 color = "#" + color;
10165 count = count || 1;
10166 duration = o.duration || 1;
10169 var b = this.getBox();
10170 var animFn = function(){
10171 var proxy = this.createProxy({
10174 visbility:"hidden",
10175 position:"absolute",
10176 "z-index":"35000", // yee haw
10177 border:"0px solid " + color
10180 var scale = Roo.isBorderBox ? 2 : 1;
10182 top:{from:b.y, to:b.y - 20},
10183 left:{from:b.x, to:b.x - 20},
10184 borderWidth:{from:0, to:10},
10185 opacity:{from:1, to:0},
10186 height:{from:b.height, to:(b.height + (20*scale))},
10187 width:{from:b.width, to:(b.width + (20*scale))}
10188 }, duration, function(){
10192 animFn.defer((duration/2)*1000, this);
10203 * Creates a pause before any subsequent queued effects begin. If there are
10204 * no effects queued after the pause it will have no effect.
10209 * @param {Number} seconds The length of time to pause (in seconds)
10210 * @return {Roo.Element} The Element
10212 pause : function(seconds){
10213 var el = this.getFxEl();
10216 el.queueFx(o, function(){
10217 setTimeout(function(){
10219 }, seconds * 1000);
10225 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10226 * using the "endOpacity" config option.
10229 // default: fade in from opacity 0 to 100%
10232 // custom: fade in from opacity 0 to 75% over 2 seconds
10233 el.fadeIn({ endOpacity: .75, duration: 2});
10235 // common config options shown with default values
10237 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10242 * @param {Object} options (optional) Object literal with any of the Fx config options
10243 * @return {Roo.Element} The Element
10245 fadeIn : function(o){
10246 var el = this.getFxEl();
10248 el.queueFx(o, function(){
10249 this.setOpacity(0);
10251 this.dom.style.visibility = 'visible';
10252 var to = o.endOpacity || 1;
10253 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10254 o, null, .5, "easeOut", function(){
10256 this.clearOpacity();
10265 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10266 * using the "endOpacity" config option.
10269 // default: fade out from the element's current opacity to 0
10272 // custom: fade out from the element's current opacity to 25% over 2 seconds
10273 el.fadeOut({ endOpacity: .25, duration: 2});
10275 // common config options shown with default values
10277 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10284 * @param {Object} options (optional) Object literal with any of the Fx config options
10285 * @return {Roo.Element} The Element
10287 fadeOut : function(o){
10288 var el = this.getFxEl();
10290 el.queueFx(o, function(){
10291 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10292 o, null, .5, "easeOut", function(){
10293 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10294 this.dom.style.display = "none";
10296 this.dom.style.visibility = "hidden";
10298 this.clearOpacity();
10306 * Animates the transition of an element's dimensions from a starting height/width
10307 * to an ending height/width.
10310 // change height and width to 100x100 pixels
10311 el.scale(100, 100);
10313 // common config options shown with default values. The height and width will default to
10314 // the element's existing values if passed as null.
10317 [element's height], {
10322 * @param {Number} width The new width (pass undefined to keep the original width)
10323 * @param {Number} height The new height (pass undefined to keep the original height)
10324 * @param {Object} options (optional) Object literal with any of the Fx config options
10325 * @return {Roo.Element} The Element
10327 scale : function(w, h, o){
10328 this.shift(Roo.apply({}, o, {
10336 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10337 * Any of these properties not specified in the config object will not be changed. This effect
10338 * requires that at least one new dimension, position or opacity setting must be passed in on
10339 * the config object in order for the function to have any effect.
10342 // slide the element horizontally to x position 200 while changing the height and opacity
10343 el.shift({ x: 200, height: 50, opacity: .8 });
10345 // common config options shown with default values.
10347 width: [element's width],
10348 height: [element's height],
10349 x: [element's x position],
10350 y: [element's y position],
10351 opacity: [element's opacity],
10356 * @param {Object} options Object literal with any of the Fx config options
10357 * @return {Roo.Element} The Element
10359 shift : function(o){
10360 var el = this.getFxEl();
10362 el.queueFx(o, function(){
10363 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10364 if(w !== undefined){
10365 a.width = {to: this.adjustWidth(w)};
10367 if(h !== undefined){
10368 a.height = {to: this.adjustHeight(h)};
10370 if(x !== undefined || y !== undefined){
10372 x !== undefined ? x : this.getX(),
10373 y !== undefined ? y : this.getY()
10376 if(op !== undefined){
10377 a.opacity = {to: op};
10379 if(o.xy !== undefined){
10380 a.points = {to: o.xy};
10382 arguments.callee.anim = this.fxanim(a,
10383 o, 'motion', .35, "easeOut", function(){
10391 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10392 * ending point of the effect.
10395 // default: slide the element downward while fading out
10398 // custom: slide the element out to the right with a 2-second duration
10399 el.ghost('r', { duration: 2 });
10401 // common config options shown with default values
10409 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10410 * @param {Object} options (optional) Object literal with any of the Fx config options
10411 * @return {Roo.Element} The Element
10413 ghost : function(anchor, o){
10414 var el = this.getFxEl();
10417 el.queueFx(o, function(){
10418 anchor = anchor || "b";
10420 // restore values after effect
10421 var r = this.getFxRestore();
10422 var w = this.getWidth(),
10423 h = this.getHeight();
10425 var st = this.dom.style;
10427 var after = function(){
10429 el.setDisplayed(false);
10435 el.setPositioning(r.pos);
10436 st.width = r.width;
10437 st.height = r.height;
10442 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10443 switch(anchor.toLowerCase()){
10470 arguments.callee.anim = this.fxanim(a,
10480 * Ensures that all effects queued after syncFx is called on the element are
10481 * run concurrently. This is the opposite of {@link #sequenceFx}.
10482 * @return {Roo.Element} The Element
10484 syncFx : function(){
10485 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10494 * Ensures that all effects queued after sequenceFx is called on the element are
10495 * run in sequence. This is the opposite of {@link #syncFx}.
10496 * @return {Roo.Element} The Element
10498 sequenceFx : function(){
10499 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10501 concurrent : false,
10508 nextFx : function(){
10509 var ef = this.fxQueue[0];
10516 * Returns true if the element has any effects actively running or queued, else returns false.
10517 * @return {Boolean} True if element has active effects, else false
10519 hasActiveFx : function(){
10520 return this.fxQueue && this.fxQueue[0];
10524 * Stops any running effects and clears the element's internal effects queue if it contains
10525 * any additional effects that haven't started yet.
10526 * @return {Roo.Element} The Element
10528 stopFx : function(){
10529 if(this.hasActiveFx()){
10530 var cur = this.fxQueue[0];
10531 if(cur && cur.anim && cur.anim.isAnimated()){
10532 this.fxQueue = [cur]; // clear out others
10533 cur.anim.stop(true);
10540 beforeFx : function(o){
10541 if(this.hasActiveFx() && !o.concurrent){
10552 * Returns true if the element is currently blocking so that no other effect can be queued
10553 * until this effect is finished, else returns false if blocking is not set. This is commonly
10554 * used to ensure that an effect initiated by a user action runs to completion prior to the
10555 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10556 * @return {Boolean} True if blocking, else false
10558 hasFxBlock : function(){
10559 var q = this.fxQueue;
10560 return q && q[0] && q[0].block;
10564 queueFx : function(o, fn){
10568 if(!this.hasFxBlock()){
10569 Roo.applyIf(o, this.fxDefaults);
10571 var run = this.beforeFx(o);
10572 fn.block = o.block;
10573 this.fxQueue.push(fn);
10585 fxWrap : function(pos, o, vis){
10587 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10590 wrapXY = this.getXY();
10592 var div = document.createElement("div");
10593 div.style.visibility = vis;
10594 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10595 wrap.setPositioning(pos);
10596 if(wrap.getStyle("position") == "static"){
10597 wrap.position("relative");
10599 this.clearPositioning('auto');
10601 wrap.dom.appendChild(this.dom);
10603 wrap.setXY(wrapXY);
10610 fxUnwrap : function(wrap, pos, o){
10611 this.clearPositioning();
10612 this.setPositioning(pos);
10614 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10620 getFxRestore : function(){
10621 var st = this.dom.style;
10622 return {pos: this.getPositioning(), width: st.width, height : st.height};
10626 afterFx : function(o){
10628 this.applyStyles(o.afterStyle);
10631 this.addClass(o.afterCls);
10633 if(o.remove === true){
10636 Roo.callback(o.callback, o.scope, [this]);
10638 this.fxQueue.shift();
10644 getFxEl : function(){ // support for composite element fx
10645 return Roo.get(this.dom);
10649 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10650 animType = animType || 'run';
10652 var anim = Roo.lib.Anim[animType](
10654 (opt.duration || defaultDur) || .35,
10655 (opt.easing || defaultEase) || 'easeOut',
10657 Roo.callback(cb, this);
10666 // backwords compat
10667 Roo.Fx.resize = Roo.Fx.scale;
10669 //When included, Roo.Fx is automatically applied to Element so that all basic
10670 //effects are available directly via the Element API
10671 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10673 * Ext JS Library 1.1.1
10674 * Copyright(c) 2006-2007, Ext JS, LLC.
10676 * Originally Released Under LGPL - original licence link has changed is not relivant.
10679 * <script type="text/javascript">
10684 * @class Roo.CompositeElement
10685 * Standard composite class. Creates a Roo.Element for every element in the collection.
10687 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10688 * actions will be performed on all the elements in this collection.</b>
10690 * All methods return <i>this</i> and can be chained.
10692 var els = Roo.select("#some-el div.some-class", true);
10693 // or select directly from an existing element
10694 var el = Roo.get('some-el');
10695 el.select('div.some-class', true);
10697 els.setWidth(100); // all elements become 100 width
10698 els.hide(true); // all elements fade out and hide
10700 els.setWidth(100).hide(true);
10703 Roo.CompositeElement = function(els){
10704 this.elements = [];
10705 this.addElements(els);
10707 Roo.CompositeElement.prototype = {
10709 addElements : function(els){
10710 if(!els) return this;
10711 if(typeof els == "string"){
10712 els = Roo.Element.selectorFunction(els);
10714 var yels = this.elements;
10715 var index = yels.length-1;
10716 for(var i = 0, len = els.length; i < len; i++) {
10717 yels[++index] = Roo.get(els[i]);
10723 * Clears this composite and adds the elements returned by the passed selector.
10724 * @param {String/Array} els A string CSS selector, an array of elements or an element
10725 * @return {CompositeElement} this
10727 fill : function(els){
10728 this.elements = [];
10734 * Filters this composite to only elements that match the passed selector.
10735 * @param {String} selector A string CSS selector
10736 * @return {CompositeElement} this
10738 filter : function(selector){
10740 this.each(function(el){
10741 if(el.is(selector)){
10742 els[els.length] = el.dom;
10749 invoke : function(fn, args){
10750 var els = this.elements;
10751 for(var i = 0, len = els.length; i < len; i++) {
10752 Roo.Element.prototype[fn].apply(els[i], args);
10757 * Adds elements to this composite.
10758 * @param {String/Array} els A string CSS selector, an array of elements or an element
10759 * @return {CompositeElement} this
10761 add : function(els){
10762 if(typeof els == "string"){
10763 this.addElements(Roo.Element.selectorFunction(els));
10764 }else if(els.length !== undefined){
10765 this.addElements(els);
10767 this.addElements([els]);
10772 * Calls the passed function passing (el, this, index) for each element in this composite.
10773 * @param {Function} fn The function to call
10774 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10775 * @return {CompositeElement} this
10777 each : function(fn, scope){
10778 var els = this.elements;
10779 for(var i = 0, len = els.length; i < len; i++){
10780 if(fn.call(scope || els[i], els[i], this, i) === false) {
10788 * Returns the Element object at the specified index
10789 * @param {Number} index
10790 * @return {Roo.Element}
10792 item : function(index){
10793 return this.elements[index] || null;
10797 * Returns the first Element
10798 * @return {Roo.Element}
10800 first : function(){
10801 return this.item(0);
10805 * Returns the last Element
10806 * @return {Roo.Element}
10809 return this.item(this.elements.length-1);
10813 * Returns the number of elements in this composite
10816 getCount : function(){
10817 return this.elements.length;
10821 * Returns true if this composite contains the passed element
10824 contains : function(el){
10825 return this.indexOf(el) !== -1;
10829 * Returns true if this composite contains the passed element
10832 indexOf : function(el){
10833 return this.elements.indexOf(Roo.get(el));
10838 * Removes the specified element(s).
10839 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10840 * or an array of any of those.
10841 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10842 * @return {CompositeElement} this
10844 removeElement : function(el, removeDom){
10845 if(el instanceof Array){
10846 for(var i = 0, len = el.length; i < len; i++){
10847 this.removeElement(el[i]);
10851 var index = typeof el == 'number' ? el : this.indexOf(el);
10854 var d = this.elements[index];
10858 d.parentNode.removeChild(d);
10861 this.elements.splice(index, 1);
10867 * Replaces the specified element with the passed element.
10868 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10870 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10871 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10872 * @return {CompositeElement} this
10874 replaceElement : function(el, replacement, domReplace){
10875 var index = typeof el == 'number' ? el : this.indexOf(el);
10878 this.elements[index].replaceWith(replacement);
10880 this.elements.splice(index, 1, Roo.get(replacement))
10887 * Removes all elements.
10889 clear : function(){
10890 this.elements = [];
10894 Roo.CompositeElement.createCall = function(proto, fnName){
10895 if(!proto[fnName]){
10896 proto[fnName] = function(){
10897 return this.invoke(fnName, arguments);
10901 for(var fnName in Roo.Element.prototype){
10902 if(typeof Roo.Element.prototype[fnName] == "function"){
10903 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10909 * Ext JS Library 1.1.1
10910 * Copyright(c) 2006-2007, Ext JS, LLC.
10912 * Originally Released Under LGPL - original licence link has changed is not relivant.
10915 * <script type="text/javascript">
10919 * @class Roo.CompositeElementLite
10920 * @extends Roo.CompositeElement
10921 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10923 var els = Roo.select("#some-el div.some-class");
10924 // or select directly from an existing element
10925 var el = Roo.get('some-el');
10926 el.select('div.some-class');
10928 els.setWidth(100); // all elements become 100 width
10929 els.hide(true); // all elements fade out and hide
10931 els.setWidth(100).hide(true);
10932 </code></pre><br><br>
10933 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10934 * actions will be performed on all the elements in this collection.</b>
10936 Roo.CompositeElementLite = function(els){
10937 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10938 this.el = new Roo.Element.Flyweight();
10940 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10941 addElements : function(els){
10943 if(els instanceof Array){
10944 this.elements = this.elements.concat(els);
10946 var yels = this.elements;
10947 var index = yels.length-1;
10948 for(var i = 0, len = els.length; i < len; i++) {
10949 yels[++index] = els[i];
10955 invoke : function(fn, args){
10956 var els = this.elements;
10958 for(var i = 0, len = els.length; i < len; i++) {
10960 Roo.Element.prototype[fn].apply(el, args);
10965 * Returns a flyweight Element of the dom element object at the specified index
10966 * @param {Number} index
10967 * @return {Roo.Element}
10969 item : function(index){
10970 if(!this.elements[index]){
10973 this.el.dom = this.elements[index];
10977 // fixes scope with flyweight
10978 addListener : function(eventName, handler, scope, opt){
10979 var els = this.elements;
10980 for(var i = 0, len = els.length; i < len; i++) {
10981 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10987 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10988 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10989 * a reference to the dom node, use el.dom.</b>
10990 * @param {Function} fn The function to call
10991 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10992 * @return {CompositeElement} this
10994 each : function(fn, scope){
10995 var els = this.elements;
10997 for(var i = 0, len = els.length; i < len; i++){
10999 if(fn.call(scope || el, el, this, i) === false){
11006 indexOf : function(el){
11007 return this.elements.indexOf(Roo.getDom(el));
11010 replaceElement : function(el, replacement, domReplace){
11011 var index = typeof el == 'number' ? el : this.indexOf(el);
11013 replacement = Roo.getDom(replacement);
11015 var d = this.elements[index];
11016 d.parentNode.insertBefore(replacement, d);
11017 d.parentNode.removeChild(d);
11019 this.elements.splice(index, 1, replacement);
11024 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11028 * Ext JS Library 1.1.1
11029 * Copyright(c) 2006-2007, Ext JS, LLC.
11031 * Originally Released Under LGPL - original licence link has changed is not relivant.
11034 * <script type="text/javascript">
11040 * @class Roo.data.Connection
11041 * @extends Roo.util.Observable
11042 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11043 * either to a configured URL, or to a URL specified at request time.<br><br>
11045 * Requests made by this class are asynchronous, and will return immediately. No data from
11046 * the server will be available to the statement immediately following the {@link #request} call.
11047 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11049 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11050 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11051 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11052 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11053 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11054 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11055 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11056 * standard DOM methods.
11058 * @param {Object} config a configuration object.
11060 Roo.data.Connection = function(config){
11061 Roo.apply(this, config);
11064 * @event beforerequest
11065 * Fires before a network request is made to retrieve a data object.
11066 * @param {Connection} conn This Connection object.
11067 * @param {Object} options The options config object passed to the {@link #request} method.
11069 "beforerequest" : true,
11071 * @event requestcomplete
11072 * Fires if the request was successfully completed.
11073 * @param {Connection} conn This Connection object.
11074 * @param {Object} response The XHR object containing the response data.
11075 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11076 * @param {Object} options The options config object passed to the {@link #request} method.
11078 "requestcomplete" : true,
11080 * @event requestexception
11081 * Fires if an error HTTP status was returned from the server.
11082 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11083 * @param {Connection} conn This Connection object.
11084 * @param {Object} response The XHR object containing the response data.
11085 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11086 * @param {Object} options The options config object passed to the {@link #request} method.
11088 "requestexception" : true
11090 Roo.data.Connection.superclass.constructor.call(this);
11093 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11095 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11098 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11099 * extra parameters to each request made by this object. (defaults to undefined)
11102 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11103 * to each request made by this object. (defaults to undefined)
11106 * @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)
11109 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11113 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11119 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11122 disableCaching: true,
11125 * Sends an HTTP request to a remote server.
11126 * @param {Object} options An object which may contain the following properties:<ul>
11127 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11128 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11129 * request, a url encoded string or a function to call to get either.</li>
11130 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11131 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11132 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11133 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11134 * <li>options {Object} The parameter to the request call.</li>
11135 * <li>success {Boolean} True if the request succeeded.</li>
11136 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11138 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11139 * The callback is passed the following parameters:<ul>
11140 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11141 * <li>options {Object} The parameter to the request call.</li>
11143 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11144 * The callback is passed the following parameters:<ul>
11145 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11146 * <li>options {Object} The parameter to the request call.</li>
11148 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11149 * for the callback function. Defaults to the browser window.</li>
11150 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11151 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11152 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11153 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11154 * params for the post data. Any params will be appended to the URL.</li>
11155 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11157 * @return {Number} transactionId
11159 request : function(o){
11160 if(this.fireEvent("beforerequest", this, o) !== false){
11163 if(typeof p == "function"){
11164 p = p.call(o.scope||window, o);
11166 if(typeof p == "object"){
11167 p = Roo.urlEncode(o.params);
11169 if(this.extraParams){
11170 var extras = Roo.urlEncode(this.extraParams);
11171 p = p ? (p + '&' + extras) : extras;
11174 var url = o.url || this.url;
11175 if(typeof url == 'function'){
11176 url = url.call(o.scope||window, o);
11180 var form = Roo.getDom(o.form);
11181 url = url || form.action;
11183 var enctype = form.getAttribute("enctype");
11184 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11185 return this.doFormUpload(o, p, url);
11187 var f = Roo.lib.Ajax.serializeForm(form);
11188 p = p ? (p + '&' + f) : f;
11191 var hs = o.headers;
11192 if(this.defaultHeaders){
11193 hs = Roo.apply(hs || {}, this.defaultHeaders);
11200 success: this.handleResponse,
11201 failure: this.handleFailure,
11203 argument: {options: o},
11204 timeout : this.timeout
11207 var method = o.method||this.method||(p ? "POST" : "GET");
11209 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11210 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11213 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11217 }else if(this.autoAbort !== false){
11221 if((method == 'GET' && p) || o.xmlData){
11222 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11225 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11226 return this.transId;
11228 Roo.callback(o.callback, o.scope, [o, null, null]);
11234 * Determine whether this object has a request outstanding.
11235 * @param {Number} transactionId (Optional) defaults to the last transaction
11236 * @return {Boolean} True if there is an outstanding request.
11238 isLoading : function(transId){
11240 return Roo.lib.Ajax.isCallInProgress(transId);
11242 return this.transId ? true : false;
11247 * Aborts any outstanding request.
11248 * @param {Number} transactionId (Optional) defaults to the last transaction
11250 abort : function(transId){
11251 if(transId || this.isLoading()){
11252 Roo.lib.Ajax.abort(transId || this.transId);
11257 handleResponse : function(response){
11258 this.transId = false;
11259 var options = response.argument.options;
11260 response.argument = options ? options.argument : null;
11261 this.fireEvent("requestcomplete", this, response, options);
11262 Roo.callback(options.success, options.scope, [response, options]);
11263 Roo.callback(options.callback, options.scope, [options, true, response]);
11267 handleFailure : function(response, e){
11268 this.transId = false;
11269 var options = response.argument.options;
11270 response.argument = options ? options.argument : null;
11271 this.fireEvent("requestexception", this, response, options, e);
11272 Roo.callback(options.failure, options.scope, [response, options]);
11273 Roo.callback(options.callback, options.scope, [options, false, response]);
11277 doFormUpload : function(o, ps, url){
11279 var frame = document.createElement('iframe');
11282 frame.className = 'x-hidden';
11284 frame.src = Roo.SSL_SECURE_URL;
11286 document.body.appendChild(frame);
11289 document.frames[id].name = id;
11292 var form = Roo.getDom(o.form);
11294 form.method = 'POST';
11295 form.enctype = form.encoding = 'multipart/form-data';
11301 if(ps){ // add dynamic params
11303 ps = Roo.urlDecode(ps, false);
11305 if(ps.hasOwnProperty(k)){
11306 hd = document.createElement('input');
11307 hd.type = 'hidden';
11310 form.appendChild(hd);
11317 var r = { // bogus response object
11322 r.argument = o ? o.argument : null;
11327 doc = frame.contentWindow.document;
11329 doc = (frame.contentDocument || window.frames[id].document);
11331 if(doc && doc.body){
11332 r.responseText = doc.body.innerHTML;
11334 if(doc && doc.XMLDocument){
11335 r.responseXML = doc.XMLDocument;
11337 r.responseXML = doc;
11344 Roo.EventManager.removeListener(frame, 'load', cb, this);
11346 this.fireEvent("requestcomplete", this, r, o);
11347 Roo.callback(o.success, o.scope, [r, o]);
11348 Roo.callback(o.callback, o.scope, [o, true, r]);
11350 setTimeout(function(){document.body.removeChild(frame);}, 100);
11353 Roo.EventManager.on(frame, 'load', cb, this);
11356 if(hiddens){ // remove dynamic params
11357 for(var i = 0, len = hiddens.length; i < len; i++){
11358 form.removeChild(hiddens[i]);
11366 * @extends Roo.data.Connection
11367 * Global Ajax request class.
11371 Roo.Ajax = new Roo.data.Connection({
11374 * @cfg {String} url @hide
11377 * @cfg {Object} extraParams @hide
11380 * @cfg {Object} defaultHeaders @hide
11383 * @cfg {String} method (Optional) @hide
11386 * @cfg {Number} timeout (Optional) @hide
11389 * @cfg {Boolean} autoAbort (Optional) @hide
11393 * @cfg {Boolean} disableCaching (Optional) @hide
11397 * @property disableCaching
11398 * True to add a unique cache-buster param to GET requests. (defaults to true)
11403 * The default URL to be used for requests to the server. (defaults to undefined)
11407 * @property extraParams
11408 * An object containing properties which are used as
11409 * extra parameters to each request made by this object. (defaults to undefined)
11413 * @property defaultHeaders
11414 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11419 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11423 * @property timeout
11424 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11429 * @property autoAbort
11430 * Whether a new request should abort any pending requests. (defaults to false)
11436 * Serialize the passed form into a url encoded string
11437 * @param {String/HTMLElement} form
11440 serializeForm : function(form){
11441 return Roo.lib.Ajax.serializeForm(form);
11445 * Ext JS Library 1.1.1
11446 * Copyright(c) 2006-2007, Ext JS, LLC.
11448 * Originally Released Under LGPL - original licence link has changed is not relivant.
11451 * <script type="text/javascript">
11456 * @extends Roo.data.Connection
11457 * Global Ajax request class.
11459 * @instanceOf Roo.data.Connection
11461 Roo.Ajax = new Roo.data.Connection({
11470 * @cfg {String} url @hide
11473 * @cfg {Object} extraParams @hide
11476 * @cfg {Object} defaultHeaders @hide
11479 * @cfg {String} method (Optional) @hide
11482 * @cfg {Number} timeout (Optional) @hide
11485 * @cfg {Boolean} autoAbort (Optional) @hide
11489 * @cfg {Boolean} disableCaching (Optional) @hide
11493 * @property disableCaching
11494 * True to add a unique cache-buster param to GET requests. (defaults to true)
11499 * The default URL to be used for requests to the server. (defaults to undefined)
11503 * @property extraParams
11504 * An object containing properties which are used as
11505 * extra parameters to each request made by this object. (defaults to undefined)
11509 * @property defaultHeaders
11510 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11515 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11519 * @property timeout
11520 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11525 * @property autoAbort
11526 * Whether a new request should abort any pending requests. (defaults to false)
11532 * Serialize the passed form into a url encoded string
11533 * @param {String/HTMLElement} form
11536 serializeForm : function(form){
11537 return Roo.lib.Ajax.serializeForm(form);
11541 * Ext JS Library 1.1.1
11542 * Copyright(c) 2006-2007, Ext JS, LLC.
11544 * Originally Released Under LGPL - original licence link has changed is not relivant.
11547 * <script type="text/javascript">
11552 * @class Roo.UpdateManager
11553 * @extends Roo.util.Observable
11554 * Provides AJAX-style update for Element object.<br><br>
11557 * // Get it from a Roo.Element object
11558 * var el = Roo.get("foo");
11559 * var mgr = el.getUpdateManager();
11560 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11562 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11564 * // or directly (returns the same UpdateManager instance)
11565 * var mgr = new Roo.UpdateManager("myElementId");
11566 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11567 * mgr.on("update", myFcnNeedsToKnow);
11569 // short handed call directly from the element object
11570 Roo.get("foo").load({
11574 text: "Loading Foo..."
11578 * Create new UpdateManager directly.
11579 * @param {String/HTMLElement/Roo.Element} el The element to update
11580 * @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).
11582 Roo.UpdateManager = function(el, forceNew){
11584 if(!forceNew && el.updateManager){
11585 return el.updateManager;
11588 * The Element object
11589 * @type Roo.Element
11593 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11596 this.defaultUrl = null;
11600 * @event beforeupdate
11601 * Fired before an update is made, return false from your handler and the update is cancelled.
11602 * @param {Roo.Element} el
11603 * @param {String/Object/Function} url
11604 * @param {String/Object} params
11606 "beforeupdate": true,
11609 * Fired after successful update is made.
11610 * @param {Roo.Element} el
11611 * @param {Object} oResponseObject The response Object
11616 * Fired on update failure.
11617 * @param {Roo.Element} el
11618 * @param {Object} oResponseObject The response Object
11622 var d = Roo.UpdateManager.defaults;
11624 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11627 this.sslBlankUrl = d.sslBlankUrl;
11629 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11632 this.disableCaching = d.disableCaching;
11634 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11637 this.indicatorText = d.indicatorText;
11639 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11642 this.showLoadIndicator = d.showLoadIndicator;
11644 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11647 this.timeout = d.timeout;
11650 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11653 this.loadScripts = d.loadScripts;
11656 * Transaction object of current executing transaction
11658 this.transaction = null;
11663 this.autoRefreshProcId = null;
11665 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11668 this.refreshDelegate = this.refresh.createDelegate(this);
11670 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11673 this.updateDelegate = this.update.createDelegate(this);
11675 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11678 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11682 this.successDelegate = this.processSuccess.createDelegate(this);
11686 this.failureDelegate = this.processFailure.createDelegate(this);
11688 if(!this.renderer){
11690 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11692 this.renderer = new Roo.UpdateManager.BasicRenderer();
11695 Roo.UpdateManager.superclass.constructor.call(this);
11698 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11700 * Get the Element this UpdateManager is bound to
11701 * @return {Roo.Element} The element
11703 getEl : function(){
11707 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11708 * @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:
11711 url: "your-url.php",<br/>
11712 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11713 callback: yourFunction,<br/>
11714 scope: yourObject, //(optional scope) <br/>
11715 discardUrl: false, <br/>
11716 nocache: false,<br/>
11717 text: "Loading...",<br/>
11719 scripts: false<br/>
11722 * The only required property is url. The optional properties nocache, text and scripts
11723 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11724 * @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}
11725 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11726 * @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.
11728 update : function(url, params, callback, discardUrl){
11729 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11730 var method = this.method, cfg;
11731 if(typeof url == "object"){ // must be config object
11734 params = params || cfg.params;
11735 callback = callback || cfg.callback;
11736 discardUrl = discardUrl || cfg.discardUrl;
11737 if(callback && cfg.scope){
11738 callback = callback.createDelegate(cfg.scope);
11740 if(typeof cfg.method != "undefined"){method = cfg.method;};
11741 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11742 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11743 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11744 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11746 this.showLoading();
11748 this.defaultUrl = url;
11750 if(typeof url == "function"){
11751 url = url.call(this);
11754 method = method || (params ? "POST" : "GET");
11755 if(method == "GET"){
11756 url = this.prepareUrl(url);
11759 var o = Roo.apply(cfg ||{}, {
11762 success: this.successDelegate,
11763 failure: this.failureDelegate,
11764 callback: undefined,
11765 timeout: (this.timeout*1000),
11766 argument: {"url": url, "form": null, "callback": callback, "params": params}
11769 this.transaction = Roo.Ajax.request(o);
11774 * 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.
11775 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11776 * @param {String/HTMLElement} form The form Id or form element
11777 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11778 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11779 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11781 formUpdate : function(form, url, reset, callback){
11782 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11783 if(typeof url == "function"){
11784 url = url.call(this);
11786 form = Roo.getDom(form);
11787 this.transaction = Roo.Ajax.request({
11790 success: this.successDelegate,
11791 failure: this.failureDelegate,
11792 timeout: (this.timeout*1000),
11793 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11795 this.showLoading.defer(1, this);
11800 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11801 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11803 refresh : function(callback){
11804 if(this.defaultUrl == null){
11807 this.update(this.defaultUrl, null, callback, true);
11811 * Set this element to auto refresh.
11812 * @param {Number} interval How often to update (in seconds).
11813 * @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)
11814 * @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}
11815 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11816 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11818 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11820 this.update(url || this.defaultUrl, params, callback, true);
11822 if(this.autoRefreshProcId){
11823 clearInterval(this.autoRefreshProcId);
11825 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11829 * Stop auto refresh on this element.
11831 stopAutoRefresh : function(){
11832 if(this.autoRefreshProcId){
11833 clearInterval(this.autoRefreshProcId);
11834 delete this.autoRefreshProcId;
11838 isAutoRefreshing : function(){
11839 return this.autoRefreshProcId ? true : false;
11842 * Called to update the element to "Loading" state. Override to perform custom action.
11844 showLoading : function(){
11845 if(this.showLoadIndicator){
11846 this.el.update(this.indicatorText);
11851 * Adds unique parameter to query string if disableCaching = true
11854 prepareUrl : function(url){
11855 if(this.disableCaching){
11856 var append = "_dc=" + (new Date().getTime());
11857 if(url.indexOf("?") !== -1){
11858 url += "&" + append;
11860 url += "?" + append;
11869 processSuccess : function(response){
11870 this.transaction = null;
11871 if(response.argument.form && response.argument.reset){
11872 try{ // put in try/catch since some older FF releases had problems with this
11873 response.argument.form.reset();
11876 if(this.loadScripts){
11877 this.renderer.render(this.el, response, this,
11878 this.updateComplete.createDelegate(this, [response]));
11880 this.renderer.render(this.el, response, this);
11881 this.updateComplete(response);
11885 updateComplete : function(response){
11886 this.fireEvent("update", this.el, response);
11887 if(typeof response.argument.callback == "function"){
11888 response.argument.callback(this.el, true, response);
11895 processFailure : function(response){
11896 this.transaction = null;
11897 this.fireEvent("failure", this.el, response);
11898 if(typeof response.argument.callback == "function"){
11899 response.argument.callback(this.el, false, response);
11904 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11905 * @param {Object} renderer The object implementing the render() method
11907 setRenderer : function(renderer){
11908 this.renderer = renderer;
11911 getRenderer : function(){
11912 return this.renderer;
11916 * Set the defaultUrl used for updates
11917 * @param {String/Function} defaultUrl The url or a function to call to get the url
11919 setDefaultUrl : function(defaultUrl){
11920 this.defaultUrl = defaultUrl;
11924 * Aborts the executing transaction
11926 abort : function(){
11927 if(this.transaction){
11928 Roo.Ajax.abort(this.transaction);
11933 * Returns true if an update is in progress
11934 * @return {Boolean}
11936 isUpdating : function(){
11937 if(this.transaction){
11938 return Roo.Ajax.isLoading(this.transaction);
11945 * @class Roo.UpdateManager.defaults
11946 * @static (not really - but it helps the doc tool)
11947 * The defaults collection enables customizing the default properties of UpdateManager
11949 Roo.UpdateManager.defaults = {
11951 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11957 * True to process scripts by default (Defaults to false).
11960 loadScripts : false,
11963 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11966 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11968 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11971 disableCaching : false,
11973 * Whether to show indicatorText when loading (Defaults to true).
11976 showLoadIndicator : true,
11978 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11981 indicatorText : '<div class="loading-indicator">Loading...</div>'
11985 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11987 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11988 * @param {String/HTMLElement/Roo.Element} el The element to update
11989 * @param {String} url The url
11990 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11991 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11994 * @member Roo.UpdateManager
11996 Roo.UpdateManager.updateElement = function(el, url, params, options){
11997 var um = Roo.get(el, true).getUpdateManager();
11998 Roo.apply(um, options);
11999 um.update(url, params, options ? options.callback : null);
12001 // alias for backwards compat
12002 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12004 * @class Roo.UpdateManager.BasicRenderer
12005 * Default Content renderer. Updates the elements innerHTML with the responseText.
12007 Roo.UpdateManager.BasicRenderer = function(){};
12009 Roo.UpdateManager.BasicRenderer.prototype = {
12011 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12012 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12013 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12014 * @param {Roo.Element} el The element being rendered
12015 * @param {Object} response The YUI Connect response object
12016 * @param {UpdateManager} updateManager The calling update manager
12017 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12019 render : function(el, response, updateManager, callback){
12020 el.update(response.responseText, updateManager.loadScripts, callback);
12025 * Ext JS Library 1.1.1
12026 * Copyright(c) 2006-2007, Ext JS, LLC.
12028 * Originally Released Under LGPL - original licence link has changed is not relivant.
12031 * <script type="text/javascript">
12035 * @class Roo.util.DelayedTask
12036 * Provides a convenient method of performing setTimeout where a new
12037 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12038 * You can use this class to buffer
12039 * the keypress events for a certain number of milliseconds, and perform only if they stop
12040 * for that amount of time.
12041 * @constructor The parameters to this constructor serve as defaults and are not required.
12042 * @param {Function} fn (optional) The default function to timeout
12043 * @param {Object} scope (optional) The default scope of that timeout
12044 * @param {Array} args (optional) The default Array of arguments
12046 Roo.util.DelayedTask = function(fn, scope, args){
12047 var id = null, d, t;
12049 var call = function(){
12050 var now = new Date().getTime();
12054 fn.apply(scope, args || []);
12058 * Cancels any pending timeout and queues a new one
12059 * @param {Number} delay The milliseconds to delay
12060 * @param {Function} newFn (optional) Overrides function passed to constructor
12061 * @param {Object} newScope (optional) Overrides scope passed to constructor
12062 * @param {Array} newArgs (optional) Overrides args passed to constructor
12064 this.delay = function(delay, newFn, newScope, newArgs){
12065 if(id && delay != d){
12069 t = new Date().getTime();
12071 scope = newScope || scope;
12072 args = newArgs || args;
12074 id = setInterval(call, d);
12079 * Cancel the last queued timeout
12081 this.cancel = function(){
12089 * Ext JS Library 1.1.1
12090 * Copyright(c) 2006-2007, Ext JS, LLC.
12092 * Originally Released Under LGPL - original licence link has changed is not relivant.
12095 * <script type="text/javascript">
12099 Roo.util.TaskRunner = function(interval){
12100 interval = interval || 10;
12101 var tasks = [], removeQueue = [];
12103 var running = false;
12105 var stopThread = function(){
12111 var startThread = function(){
12114 id = setInterval(runTasks, interval);
12118 var removeTask = function(task){
12119 removeQueue.push(task);
12125 var runTasks = function(){
12126 if(removeQueue.length > 0){
12127 for(var i = 0, len = removeQueue.length; i < len; i++){
12128 tasks.remove(removeQueue[i]);
12131 if(tasks.length < 1){
12136 var now = new Date().getTime();
12137 for(var i = 0, len = tasks.length; i < len; ++i){
12139 var itime = now - t.taskRunTime;
12140 if(t.interval <= itime){
12141 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12142 t.taskRunTime = now;
12143 if(rt === false || t.taskRunCount === t.repeat){
12148 if(t.duration && t.duration <= (now - t.taskStartTime)){
12155 * Queues a new task.
12156 * @param {Object} task
12158 this.start = function(task){
12160 task.taskStartTime = new Date().getTime();
12161 task.taskRunTime = 0;
12162 task.taskRunCount = 0;
12167 this.stop = function(task){
12172 this.stopAll = function(){
12174 for(var i = 0, len = tasks.length; i < len; i++){
12175 if(tasks[i].onStop){
12184 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12186 * Ext JS Library 1.1.1
12187 * Copyright(c) 2006-2007, Ext JS, LLC.
12189 * Originally Released Under LGPL - original licence link has changed is not relivant.
12192 * <script type="text/javascript">
12197 * @class Roo.util.MixedCollection
12198 * @extends Roo.util.Observable
12199 * A Collection class that maintains both numeric indexes and keys and exposes events.
12201 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12202 * collection (defaults to false)
12203 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12204 * and return the key value for that item. This is used when available to look up the key on items that
12205 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12206 * equivalent to providing an implementation for the {@link #getKey} method.
12208 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12216 * Fires when the collection is cleared.
12221 * Fires when an item is added to the collection.
12222 * @param {Number} index The index at which the item was added.
12223 * @param {Object} o The item added.
12224 * @param {String} key The key associated with the added item.
12229 * Fires when an item is replaced in the collection.
12230 * @param {String} key he key associated with the new added.
12231 * @param {Object} old The item being replaced.
12232 * @param {Object} new The new item.
12237 * Fires when an item is removed from the collection.
12238 * @param {Object} o The item being removed.
12239 * @param {String} key (optional) The key associated with the removed item.
12244 this.allowFunctions = allowFunctions === true;
12246 this.getKey = keyFn;
12248 Roo.util.MixedCollection.superclass.constructor.call(this);
12251 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12252 allowFunctions : false,
12255 * Adds an item to the collection.
12256 * @param {String} key The key to associate with the item
12257 * @param {Object} o The item to add.
12258 * @return {Object} The item added.
12260 add : function(key, o){
12261 if(arguments.length == 1){
12263 key = this.getKey(o);
12265 if(typeof key == "undefined" || key === null){
12267 this.items.push(o);
12268 this.keys.push(null);
12270 var old = this.map[key];
12272 return this.replace(key, o);
12275 this.items.push(o);
12277 this.keys.push(key);
12279 this.fireEvent("add", this.length-1, o, key);
12284 * MixedCollection has a generic way to fetch keys if you implement getKey.
12287 var mc = new Roo.util.MixedCollection();
12288 mc.add(someEl.dom.id, someEl);
12289 mc.add(otherEl.dom.id, otherEl);
12293 var mc = new Roo.util.MixedCollection();
12294 mc.getKey = function(el){
12300 // or via the constructor
12301 var mc = new Roo.util.MixedCollection(false, function(el){
12307 * @param o {Object} The item for which to find the key.
12308 * @return {Object} The key for the passed item.
12310 getKey : function(o){
12315 * Replaces an item in the collection.
12316 * @param {String} key The key associated with the item to replace, or the item to replace.
12317 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12318 * @return {Object} The new item.
12320 replace : function(key, o){
12321 if(arguments.length == 1){
12323 key = this.getKey(o);
12325 var old = this.item(key);
12326 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12327 return this.add(key, o);
12329 var index = this.indexOfKey(key);
12330 this.items[index] = o;
12332 this.fireEvent("replace", key, old, o);
12337 * Adds all elements of an Array or an Object to the collection.
12338 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12339 * an Array of values, each of which are added to the collection.
12341 addAll : function(objs){
12342 if(arguments.length > 1 || objs instanceof Array){
12343 var args = arguments.length > 1 ? arguments : objs;
12344 for(var i = 0, len = args.length; i < len; i++){
12348 for(var key in objs){
12349 if(this.allowFunctions || typeof objs[key] != "function"){
12350 this.add(key, objs[key]);
12357 * Executes the specified function once for every item in the collection, passing each
12358 * item as the first and only parameter. returning false from the function will stop the iteration.
12359 * @param {Function} fn The function to execute for each item.
12360 * @param {Object} scope (optional) The scope in which to execute the function.
12362 each : function(fn, scope){
12363 var items = [].concat(this.items); // each safe for removal
12364 for(var i = 0, len = items.length; i < len; i++){
12365 if(fn.call(scope || items[i], items[i], i, len) === false){
12372 * Executes the specified function once for every key in the collection, passing each
12373 * key, and its associated item as the first two parameters.
12374 * @param {Function} fn The function to execute for each item.
12375 * @param {Object} scope (optional) The scope in which to execute the function.
12377 eachKey : function(fn, scope){
12378 for(var i = 0, len = this.keys.length; i < len; i++){
12379 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12384 * Returns the first item in the collection which elicits a true return value from the
12385 * passed selection function.
12386 * @param {Function} fn The selection function to execute for each item.
12387 * @param {Object} scope (optional) The scope in which to execute the function.
12388 * @return {Object} The first item in the collection which returned true from the selection function.
12390 find : function(fn, scope){
12391 for(var i = 0, len = this.items.length; i < len; i++){
12392 if(fn.call(scope || window, this.items[i], this.keys[i])){
12393 return this.items[i];
12400 * Inserts an item at the specified index in the collection.
12401 * @param {Number} index The index to insert the item at.
12402 * @param {String} key The key to associate with the new item, or the item itself.
12403 * @param {Object} o (optional) If the second parameter was a key, the new item.
12404 * @return {Object} The item inserted.
12406 insert : function(index, key, o){
12407 if(arguments.length == 2){
12409 key = this.getKey(o);
12411 if(index >= this.length){
12412 return this.add(key, o);
12415 this.items.splice(index, 0, o);
12416 if(typeof key != "undefined" && key != null){
12419 this.keys.splice(index, 0, key);
12420 this.fireEvent("add", index, o, key);
12425 * Removed an item from the collection.
12426 * @param {Object} o The item to remove.
12427 * @return {Object} The item removed.
12429 remove : function(o){
12430 return this.removeAt(this.indexOf(o));
12434 * Remove an item from a specified index in the collection.
12435 * @param {Number} index The index within the collection of the item to remove.
12437 removeAt : function(index){
12438 if(index < this.length && index >= 0){
12440 var o = this.items[index];
12441 this.items.splice(index, 1);
12442 var key = this.keys[index];
12443 if(typeof key != "undefined"){
12444 delete this.map[key];
12446 this.keys.splice(index, 1);
12447 this.fireEvent("remove", o, key);
12452 * Removed an item associated with the passed key fom the collection.
12453 * @param {String} key The key of the item to remove.
12455 removeKey : function(key){
12456 return this.removeAt(this.indexOfKey(key));
12460 * Returns the number of items in the collection.
12461 * @return {Number} the number of items in the collection.
12463 getCount : function(){
12464 return this.length;
12468 * Returns index within the collection of the passed Object.
12469 * @param {Object} o The item to find the index of.
12470 * @return {Number} index of the item.
12472 indexOf : function(o){
12473 if(!this.items.indexOf){
12474 for(var i = 0, len = this.items.length; i < len; i++){
12475 if(this.items[i] == o) return i;
12479 return this.items.indexOf(o);
12484 * Returns index within the collection of the passed key.
12485 * @param {String} key The key to find the index of.
12486 * @return {Number} index of the key.
12488 indexOfKey : function(key){
12489 if(!this.keys.indexOf){
12490 for(var i = 0, len = this.keys.length; i < len; i++){
12491 if(this.keys[i] == key) return i;
12495 return this.keys.indexOf(key);
12500 * Returns the item associated with the passed key OR index. Key has priority over index.
12501 * @param {String/Number} key The key or index of the item.
12502 * @return {Object} The item associated with the passed key.
12504 item : function(key){
12505 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12506 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12510 * Returns the item at the specified index.
12511 * @param {Number} index The index of the item.
12514 itemAt : function(index){
12515 return this.items[index];
12519 * Returns the item associated with the passed key.
12520 * @param {String/Number} key The key of the item.
12521 * @return {Object} The item associated with the passed key.
12523 key : function(key){
12524 return this.map[key];
12528 * Returns true if the collection contains the passed Object as an item.
12529 * @param {Object} o The Object to look for in the collection.
12530 * @return {Boolean} True if the collection contains the Object as an item.
12532 contains : function(o){
12533 return this.indexOf(o) != -1;
12537 * Returns true if the collection contains the passed Object as a key.
12538 * @param {String} key The key to look for in the collection.
12539 * @return {Boolean} True if the collection contains the Object as a key.
12541 containsKey : function(key){
12542 return typeof this.map[key] != "undefined";
12546 * Removes all items from the collection.
12548 clear : function(){
12553 this.fireEvent("clear");
12557 * Returns the first item in the collection.
12558 * @return {Object} the first item in the collection..
12560 first : function(){
12561 return this.items[0];
12565 * Returns the last item in the collection.
12566 * @return {Object} the last item in the collection..
12569 return this.items[this.length-1];
12572 _sort : function(property, dir, fn){
12573 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12574 fn = fn || function(a, b){
12577 var c = [], k = this.keys, items = this.items;
12578 for(var i = 0, len = items.length; i < len; i++){
12579 c[c.length] = {key: k[i], value: items[i], index: i};
12581 c.sort(function(a, b){
12582 var v = fn(a[property], b[property]) * dsc;
12584 v = (a.index < b.index ? -1 : 1);
12588 for(var i = 0, len = c.length; i < len; i++){
12589 items[i] = c[i].value;
12592 this.fireEvent("sort", this);
12596 * Sorts this collection with the passed comparison function
12597 * @param {String} direction (optional) "ASC" or "DESC"
12598 * @param {Function} fn (optional) comparison function
12600 sort : function(dir, fn){
12601 this._sort("value", dir, fn);
12605 * Sorts this collection by keys
12606 * @param {String} direction (optional) "ASC" or "DESC"
12607 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12609 keySort : function(dir, fn){
12610 this._sort("key", dir, fn || function(a, b){
12611 return String(a).toUpperCase()-String(b).toUpperCase();
12616 * Returns a range of items in this collection
12617 * @param {Number} startIndex (optional) defaults to 0
12618 * @param {Number} endIndex (optional) default to the last item
12619 * @return {Array} An array of items
12621 getRange : function(start, end){
12622 var items = this.items;
12623 if(items.length < 1){
12626 start = start || 0;
12627 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12630 for(var i = start; i <= end; i++) {
12631 r[r.length] = items[i];
12634 for(var i = start; i >= end; i--) {
12635 r[r.length] = items[i];
12642 * Filter the <i>objects</i> in this collection by a specific property.
12643 * Returns a new collection that has been filtered.
12644 * @param {String} property A property on your objects
12645 * @param {String/RegExp} value Either string that the property values
12646 * should start with or a RegExp to test against the property
12647 * @return {MixedCollection} The new filtered collection
12649 filter : function(property, value){
12650 if(!value.exec){ // not a regex
12651 value = String(value);
12652 if(value.length == 0){
12653 return this.clone();
12655 value = new RegExp("^" + Roo.escapeRe(value), "i");
12657 return this.filterBy(function(o){
12658 return o && value.test(o[property]);
12663 * Filter by a function. * Returns a new collection that has been filtered.
12664 * The passed function will be called with each
12665 * object in the collection. If the function returns true, the value is included
12666 * otherwise it is filtered.
12667 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12668 * @param {Object} scope (optional) The scope of the function (defaults to this)
12669 * @return {MixedCollection} The new filtered collection
12671 filterBy : function(fn, scope){
12672 var r = new Roo.util.MixedCollection();
12673 r.getKey = this.getKey;
12674 var k = this.keys, it = this.items;
12675 for(var i = 0, len = it.length; i < len; i++){
12676 if(fn.call(scope||this, it[i], k[i])){
12677 r.add(k[i], it[i]);
12684 * Creates a duplicate of this collection
12685 * @return {MixedCollection}
12687 clone : function(){
12688 var r = new Roo.util.MixedCollection();
12689 var k = this.keys, it = this.items;
12690 for(var i = 0, len = it.length; i < len; i++){
12691 r.add(k[i], it[i]);
12693 r.getKey = this.getKey;
12698 * Returns the item associated with the passed key or index.
12700 * @param {String/Number} key The key or index of the item.
12701 * @return {Object} The item associated with the passed key.
12703 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12705 * Ext JS Library 1.1.1
12706 * Copyright(c) 2006-2007, Ext JS, LLC.
12708 * Originally Released Under LGPL - original licence link has changed is not relivant.
12711 * <script type="text/javascript">
12714 * @class Roo.util.JSON
12715 * Modified version of Douglas Crockford"s json.js that doesn"t
12716 * mess with the Object prototype
12717 * http://www.json.org/js.html
12720 Roo.util.JSON = new (function(){
12721 var useHasOwn = {}.hasOwnProperty ? true : false;
12723 // crashes Safari in some instances
12724 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12726 var pad = function(n) {
12727 return n < 10 ? "0" + n : n;
12740 var encodeString = function(s){
12741 if (/["\\\x00-\x1f]/.test(s)) {
12742 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12747 c = b.charCodeAt();
12749 Math.floor(c / 16).toString(16) +
12750 (c % 16).toString(16);
12753 return '"' + s + '"';
12756 var encodeArray = function(o){
12757 var a = ["["], b, i, l = o.length, v;
12758 for (i = 0; i < l; i += 1) {
12760 switch (typeof v) {
12769 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12777 var encodeDate = function(o){
12778 return '"' + o.getFullYear() + "-" +
12779 pad(o.getMonth() + 1) + "-" +
12780 pad(o.getDate()) + "T" +
12781 pad(o.getHours()) + ":" +
12782 pad(o.getMinutes()) + ":" +
12783 pad(o.getSeconds()) + '"';
12787 * Encodes an Object, Array or other value
12788 * @param {Mixed} o The variable to encode
12789 * @return {String} The JSON string
12791 this.encode = function(o)
12793 // should this be extended to fully wrap stringify..
12795 if(typeof o == "undefined" || o === null){
12797 }else if(o instanceof Array){
12798 return encodeArray(o);
12799 }else if(o instanceof Date){
12800 return encodeDate(o);
12801 }else if(typeof o == "string"){
12802 return encodeString(o);
12803 }else if(typeof o == "number"){
12804 return isFinite(o) ? String(o) : "null";
12805 }else if(typeof o == "boolean"){
12808 var a = ["{"], b, i, v;
12810 if(!useHasOwn || o.hasOwnProperty(i)) {
12812 switch (typeof v) {
12821 a.push(this.encode(i), ":",
12822 v === null ? "null" : this.encode(v));
12833 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12834 * @param {String} json The JSON string
12835 * @return {Object} The resulting object
12837 this.decode = function(json){
12839 return /** eval:var:json */ eval("(" + json + ')');
12843 * Shorthand for {@link Roo.util.JSON#encode}
12844 * @member Roo encode
12846 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12848 * Shorthand for {@link Roo.util.JSON#decode}
12849 * @member Roo decode
12851 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12854 * Ext JS Library 1.1.1
12855 * Copyright(c) 2006-2007, Ext JS, LLC.
12857 * Originally Released Under LGPL - original licence link has changed is not relivant.
12860 * <script type="text/javascript">
12864 * @class Roo.util.Format
12865 * Reusable data formatting functions
12868 Roo.util.Format = function(){
12869 var trimRe = /^\s+|\s+$/g;
12872 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12873 * @param {String} value The string to truncate
12874 * @param {Number} length The maximum length to allow before truncating
12875 * @return {String} The converted text
12877 ellipsis : function(value, len){
12878 if(value && value.length > len){
12879 return value.substr(0, len-3)+"...";
12885 * Checks a reference and converts it to empty string if it is undefined
12886 * @param {Mixed} value Reference to check
12887 * @return {Mixed} Empty string if converted, otherwise the original value
12889 undef : function(value){
12890 return typeof value != "undefined" ? value : "";
12894 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12895 * @param {String} value The string to encode
12896 * @return {String} The encoded text
12898 htmlEncode : function(value){
12899 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12903 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12904 * @param {String} value The string to decode
12905 * @return {String} The decoded text
12907 htmlDecode : function(value){
12908 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12912 * Trims any whitespace from either side of a string
12913 * @param {String} value The text to trim
12914 * @return {String} The trimmed text
12916 trim : function(value){
12917 return String(value).replace(trimRe, "");
12921 * Returns a substring from within an original string
12922 * @param {String} value The original text
12923 * @param {Number} start The start index of the substring
12924 * @param {Number} length The length of the substring
12925 * @return {String} The substring
12927 substr : function(value, start, length){
12928 return String(value).substr(start, length);
12932 * Converts a string to all lower case letters
12933 * @param {String} value The text to convert
12934 * @return {String} The converted text
12936 lowercase : function(value){
12937 return String(value).toLowerCase();
12941 * Converts a string to all upper case letters
12942 * @param {String} value The text to convert
12943 * @return {String} The converted text
12945 uppercase : function(value){
12946 return String(value).toUpperCase();
12950 * Converts the first character only of a string to upper case
12951 * @param {String} value The text to convert
12952 * @return {String} The converted text
12954 capitalize : function(value){
12955 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12959 call : function(value, fn){
12960 if(arguments.length > 2){
12961 var args = Array.prototype.slice.call(arguments, 2);
12962 args.unshift(value);
12964 return /** eval:var:value */ eval(fn).apply(window, args);
12966 /** eval:var:value */
12967 return /** eval:var:value */ eval(fn).call(window, value);
12973 * safer version of Math.toFixed..??/
12974 * @param {Number/String} value The numeric value to format
12975 * @param {Number/String} value Decimal places
12976 * @return {String} The formatted currency string
12978 toFixed : function(v, n)
12980 // why not use to fixed - precision is buggered???
12982 return Math.round(v-0);
12984 var fact = Math.pow(10,n+1);
12985 v = (Math.round((v-0)*fact))/fact;
12986 var z = (''+fact).substring(2);
12987 if (v == Math.floor(v)) {
12988 return Math.floor(v) + '.' + z;
12991 // now just padd decimals..
12992 var ps = String(v).split('.');
12993 var fd = (ps[1] + z);
12994 var r = fd.substring(0,n);
12995 var rm = fd.substring(n);
12997 return ps[0] + '.' + r;
12999 r*=1; // turn it into a number;
13001 if (String(r).length != n) {
13004 r = String(r).substring(1); // chop the end off.
13007 return ps[0] + '.' + r;
13012 * Format a number as US currency
13013 * @param {Number/String} value The numeric value to format
13014 * @return {String} The formatted currency string
13016 usMoney : function(v){
13017 v = (Math.round((v-0)*100))/100;
13018 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13020 var ps = v.split('.');
13022 var sub = ps[1] ? '.'+ ps[1] : '.00';
13023 var r = /(\d+)(\d{3})/;
13024 while (r.test(whole)) {
13025 whole = whole.replace(r, '$1' + ',' + '$2');
13027 return "$" + whole + sub ;
13031 * Parse a value into a formatted date using the specified format pattern.
13032 * @param {Mixed} value The value to format
13033 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13034 * @return {String} The formatted date string
13036 date : function(v, format){
13040 if(!(v instanceof Date)){
13041 v = new Date(Date.parse(v));
13043 return v.dateFormat(format || "m/d/Y");
13047 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13048 * @param {String} format Any valid date format string
13049 * @return {Function} The date formatting function
13051 dateRenderer : function(format){
13052 return function(v){
13053 return Roo.util.Format.date(v, format);
13058 stripTagsRE : /<\/?[^>]+>/gi,
13061 * Strips all HTML tags
13062 * @param {Mixed} value The text from which to strip tags
13063 * @return {String} The stripped text
13065 stripTags : function(v){
13066 return !v ? v : String(v).replace(this.stripTagsRE, "");
13071 * Ext JS Library 1.1.1
13072 * Copyright(c) 2006-2007, Ext JS, LLC.
13074 * Originally Released Under LGPL - original licence link has changed is not relivant.
13077 * <script type="text/javascript">
13084 * @class Roo.MasterTemplate
13085 * @extends Roo.Template
13086 * Provides a template that can have child templates. The syntax is:
13088 var t = new Roo.MasterTemplate(
13089 '<select name="{name}">',
13090 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13093 t.add('options', {value: 'foo', text: 'bar'});
13094 // or you can add multiple child elements in one shot
13095 t.addAll('options', [
13096 {value: 'foo', text: 'bar'},
13097 {value: 'foo2', text: 'bar2'},
13098 {value: 'foo3', text: 'bar3'}
13100 // then append, applying the master template values
13101 t.append('my-form', {name: 'my-select'});
13103 * A name attribute for the child template is not required if you have only one child
13104 * template or you want to refer to them by index.
13106 Roo.MasterTemplate = function(){
13107 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13108 this.originalHtml = this.html;
13110 var m, re = this.subTemplateRe;
13113 while(m = re.exec(this.html)){
13114 var name = m[1], content = m[2];
13119 tpl : new Roo.Template(content)
13122 st[name] = st[subIndex];
13124 st[subIndex].tpl.compile();
13125 st[subIndex].tpl.call = this.call.createDelegate(this);
13128 this.subCount = subIndex;
13131 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13133 * The regular expression used to match sub templates
13137 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13140 * Applies the passed values to a child template.
13141 * @param {String/Number} name (optional) The name or index of the child template
13142 * @param {Array/Object} values The values to be applied to the template
13143 * @return {MasterTemplate} this
13145 add : function(name, values){
13146 if(arguments.length == 1){
13147 values = arguments[0];
13150 var s = this.subs[name];
13151 s.buffer[s.buffer.length] = s.tpl.apply(values);
13156 * Applies all the passed values to a child template.
13157 * @param {String/Number} name (optional) The name or index of the child template
13158 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13159 * @param {Boolean} reset (optional) True to reset the template first
13160 * @return {MasterTemplate} this
13162 fill : function(name, values, reset){
13164 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13172 for(var i = 0, len = values.length; i < len; i++){
13173 this.add(name, values[i]);
13179 * Resets the template for reuse
13180 * @return {MasterTemplate} this
13182 reset : function(){
13184 for(var i = 0; i < this.subCount; i++){
13190 applyTemplate : function(values){
13192 var replaceIndex = -1;
13193 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13194 return s[++replaceIndex].buffer.join("");
13196 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13199 apply : function(){
13200 return this.applyTemplate.apply(this, arguments);
13203 compile : function(){return this;}
13207 * Alias for fill().
13210 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13212 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13213 * var tpl = Roo.MasterTemplate.from('element-id');
13214 * @param {String/HTMLElement} el
13215 * @param {Object} config
13218 Roo.MasterTemplate.from = function(el, config){
13219 el = Roo.getDom(el);
13220 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13223 * Ext JS Library 1.1.1
13224 * Copyright(c) 2006-2007, Ext JS, LLC.
13226 * Originally Released Under LGPL - original licence link has changed is not relivant.
13229 * <script type="text/javascript">
13234 * @class Roo.util.CSS
13235 * Utility class for manipulating CSS rules
13238 Roo.util.CSS = function(){
13240 var doc = document;
13242 var camelRe = /(-[a-z])/gi;
13243 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13247 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13248 * tag and appended to the HEAD of the document.
13249 * @param {String|Object} cssText The text containing the css rules
13250 * @param {String} id An id to add to the stylesheet for later removal
13251 * @return {StyleSheet}
13253 createStyleSheet : function(cssText, id){
13255 var head = doc.getElementsByTagName("head")[0];
13256 var nrules = doc.createElement("style");
13257 nrules.setAttribute("type", "text/css");
13259 nrules.setAttribute("id", id);
13261 if (typeof(cssText) != 'string') {
13262 // support object maps..
13263 // not sure if this a good idea..
13264 // perhaps it should be merged with the general css handling
13265 // and handle js style props.
13266 var cssTextNew = [];
13267 for(var n in cssText) {
13269 for(var k in cssText[n]) {
13270 citems.push( k + ' : ' +cssText[n][k] + ';' );
13272 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13275 cssText = cssTextNew.join("\n");
13281 head.appendChild(nrules);
13282 ss = nrules.styleSheet;
13283 ss.cssText = cssText;
13286 nrules.appendChild(doc.createTextNode(cssText));
13288 nrules.cssText = cssText;
13290 head.appendChild(nrules);
13291 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13293 this.cacheStyleSheet(ss);
13298 * Removes a style or link tag by id
13299 * @param {String} id The id of the tag
13301 removeStyleSheet : function(id){
13302 var existing = doc.getElementById(id);
13304 existing.parentNode.removeChild(existing);
13309 * Dynamically swaps an existing stylesheet reference for a new one
13310 * @param {String} id The id of an existing link tag to remove
13311 * @param {String} url The href of the new stylesheet to include
13313 swapStyleSheet : function(id, url){
13314 this.removeStyleSheet(id);
13315 var ss = doc.createElement("link");
13316 ss.setAttribute("rel", "stylesheet");
13317 ss.setAttribute("type", "text/css");
13318 ss.setAttribute("id", id);
13319 ss.setAttribute("href", url);
13320 doc.getElementsByTagName("head")[0].appendChild(ss);
13324 * Refresh the rule cache if you have dynamically added stylesheets
13325 * @return {Object} An object (hash) of rules indexed by selector
13327 refreshCache : function(){
13328 return this.getRules(true);
13332 cacheStyleSheet : function(stylesheet){
13336 try{// try catch for cross domain access issue
13337 var ssRules = stylesheet.cssRules || stylesheet.rules;
13338 for(var j = ssRules.length-1; j >= 0; --j){
13339 rules[ssRules[j].selectorText] = ssRules[j];
13345 * Gets all css rules for the document
13346 * @param {Boolean} refreshCache true to refresh the internal cache
13347 * @return {Object} An object (hash) of rules indexed by selector
13349 getRules : function(refreshCache){
13350 if(rules == null || refreshCache){
13352 var ds = doc.styleSheets;
13353 for(var i =0, len = ds.length; i < len; i++){
13355 this.cacheStyleSheet(ds[i]);
13363 * Gets an an individual CSS rule by selector(s)
13364 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13365 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13366 * @return {CSSRule} The CSS rule or null if one is not found
13368 getRule : function(selector, refreshCache){
13369 var rs = this.getRules(refreshCache);
13370 if(!(selector instanceof Array)){
13371 return rs[selector];
13373 for(var i = 0; i < selector.length; i++){
13374 if(rs[selector[i]]){
13375 return rs[selector[i]];
13383 * Updates a rule property
13384 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13385 * @param {String} property The css property
13386 * @param {String} value The new value for the property
13387 * @return {Boolean} true If a rule was found and updated
13389 updateRule : function(selector, property, value){
13390 if(!(selector instanceof Array)){
13391 var rule = this.getRule(selector);
13393 rule.style[property.replace(camelRe, camelFn)] = value;
13397 for(var i = 0; i < selector.length; i++){
13398 if(this.updateRule(selector[i], property, value)){
13408 * Ext JS Library 1.1.1
13409 * Copyright(c) 2006-2007, Ext JS, LLC.
13411 * Originally Released Under LGPL - original licence link has changed is not relivant.
13414 * <script type="text/javascript">
13420 * @class Roo.util.ClickRepeater
13421 * @extends Roo.util.Observable
13423 * A wrapper class which can be applied to any element. Fires a "click" event while the
13424 * mouse is pressed. The interval between firings may be specified in the config but
13425 * defaults to 10 milliseconds.
13427 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13429 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13430 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13431 * Similar to an autorepeat key delay.
13432 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13433 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13434 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13435 * "interval" and "delay" are ignored. "immediate" is honored.
13436 * @cfg {Boolean} preventDefault True to prevent the default click event
13437 * @cfg {Boolean} stopDefault True to stop the default click event
13440 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13441 * 2007-02-02 jvs Renamed to ClickRepeater
13442 * 2007-02-03 jvs Modifications for FF Mac and Safari
13445 * @param {String/HTMLElement/Element} el The element to listen on
13446 * @param {Object} config
13448 Roo.util.ClickRepeater = function(el, config)
13450 this.el = Roo.get(el);
13451 this.el.unselectable();
13453 Roo.apply(this, config);
13458 * Fires when the mouse button is depressed.
13459 * @param {Roo.util.ClickRepeater} this
13461 "mousedown" : true,
13464 * Fires on a specified interval during the time the element is pressed.
13465 * @param {Roo.util.ClickRepeater} this
13470 * Fires when the mouse key is released.
13471 * @param {Roo.util.ClickRepeater} this
13476 this.el.on("mousedown", this.handleMouseDown, this);
13477 if(this.preventDefault || this.stopDefault){
13478 this.el.on("click", function(e){
13479 if(this.preventDefault){
13480 e.preventDefault();
13482 if(this.stopDefault){
13488 // allow inline handler
13490 this.on("click", this.handler, this.scope || this);
13493 Roo.util.ClickRepeater.superclass.constructor.call(this);
13496 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13499 preventDefault : true,
13500 stopDefault : false,
13504 handleMouseDown : function(){
13505 clearTimeout(this.timer);
13507 if(this.pressClass){
13508 this.el.addClass(this.pressClass);
13510 this.mousedownTime = new Date();
13512 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13513 this.el.on("mouseout", this.handleMouseOut, this);
13515 this.fireEvent("mousedown", this);
13516 this.fireEvent("click", this);
13518 this.timer = this.click.defer(this.delay || this.interval, this);
13522 click : function(){
13523 this.fireEvent("click", this);
13524 this.timer = this.click.defer(this.getInterval(), this);
13528 getInterval: function(){
13529 if(!this.accelerate){
13530 return this.interval;
13532 var pressTime = this.mousedownTime.getElapsed();
13533 if(pressTime < 500){
13535 }else if(pressTime < 1700){
13537 }else if(pressTime < 2600){
13539 }else if(pressTime < 3500){
13541 }else if(pressTime < 4400){
13543 }else if(pressTime < 5300){
13545 }else if(pressTime < 6200){
13553 handleMouseOut : function(){
13554 clearTimeout(this.timer);
13555 if(this.pressClass){
13556 this.el.removeClass(this.pressClass);
13558 this.el.on("mouseover", this.handleMouseReturn, this);
13562 handleMouseReturn : function(){
13563 this.el.un("mouseover", this.handleMouseReturn);
13564 if(this.pressClass){
13565 this.el.addClass(this.pressClass);
13571 handleMouseUp : function(){
13572 clearTimeout(this.timer);
13573 this.el.un("mouseover", this.handleMouseReturn);
13574 this.el.un("mouseout", this.handleMouseOut);
13575 Roo.get(document).un("mouseup", this.handleMouseUp);
13576 this.el.removeClass(this.pressClass);
13577 this.fireEvent("mouseup", this);
13581 * Ext JS Library 1.1.1
13582 * Copyright(c) 2006-2007, Ext JS, LLC.
13584 * Originally Released Under LGPL - original licence link has changed is not relivant.
13587 * <script type="text/javascript">
13592 * @class Roo.KeyNav
13593 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13594 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13595 * way to implement custom navigation schemes for any UI component.</p>
13596 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13597 * pageUp, pageDown, del, home, end. Usage:</p>
13599 var nav = new Roo.KeyNav("my-element", {
13600 "left" : function(e){
13601 this.moveLeft(e.ctrlKey);
13603 "right" : function(e){
13604 this.moveRight(e.ctrlKey);
13606 "enter" : function(e){
13613 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13614 * @param {Object} config The config
13616 Roo.KeyNav = function(el, config){
13617 this.el = Roo.get(el);
13618 Roo.apply(this, config);
13619 if(!this.disabled){
13620 this.disabled = true;
13625 Roo.KeyNav.prototype = {
13627 * @cfg {Boolean} disabled
13628 * True to disable this KeyNav instance (defaults to false)
13632 * @cfg {String} defaultEventAction
13633 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13634 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13635 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13637 defaultEventAction: "stopEvent",
13639 * @cfg {Boolean} forceKeyDown
13640 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13641 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13642 * handle keydown instead of keypress.
13644 forceKeyDown : false,
13647 prepareEvent : function(e){
13648 var k = e.getKey();
13649 var h = this.keyToHandler[k];
13650 //if(h && this[h]){
13651 // e.stopPropagation();
13653 if(Roo.isSafari && h && k >= 37 && k <= 40){
13659 relay : function(e){
13660 var k = e.getKey();
13661 var h = this.keyToHandler[k];
13663 if(this.doRelay(e, this[h], h) !== true){
13664 e[this.defaultEventAction]();
13670 doRelay : function(e, h, hname){
13671 return h.call(this.scope || this, e);
13674 // possible handlers
13688 // quick lookup hash
13705 * Enable this KeyNav
13707 enable: function(){
13709 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13710 // the EventObject will normalize Safari automatically
13711 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13712 this.el.on("keydown", this.relay, this);
13714 this.el.on("keydown", this.prepareEvent, this);
13715 this.el.on("keypress", this.relay, this);
13717 this.disabled = false;
13722 * Disable this KeyNav
13724 disable: function(){
13725 if(!this.disabled){
13726 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13727 this.el.un("keydown", this.relay);
13729 this.el.un("keydown", this.prepareEvent);
13730 this.el.un("keypress", this.relay);
13732 this.disabled = true;
13737 * Ext JS Library 1.1.1
13738 * Copyright(c) 2006-2007, Ext JS, LLC.
13740 * Originally Released Under LGPL - original licence link has changed is not relivant.
13743 * <script type="text/javascript">
13748 * @class Roo.KeyMap
13749 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13750 * The constructor accepts the same config object as defined by {@link #addBinding}.
13751 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13752 * combination it will call the function with this signature (if the match is a multi-key
13753 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13754 * A KeyMap can also handle a string representation of keys.<br />
13757 // map one key by key code
13758 var map = new Roo.KeyMap("my-element", {
13759 key: 13, // or Roo.EventObject.ENTER
13764 // map multiple keys to one action by string
13765 var map = new Roo.KeyMap("my-element", {
13771 // map multiple keys to multiple actions by strings and array of codes
13772 var map = new Roo.KeyMap("my-element", [
13775 fn: function(){ alert("Return was pressed"); }
13778 fn: function(){ alert('a, b or c was pressed'); }
13783 fn: function(){ alert('Control + shift + tab was pressed.'); }
13787 * <b>Note: A KeyMap starts enabled</b>
13789 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13790 * @param {Object} config The config (see {@link #addBinding})
13791 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13793 Roo.KeyMap = function(el, config, eventName){
13794 this.el = Roo.get(el);
13795 this.eventName = eventName || "keydown";
13796 this.bindings = [];
13798 this.addBinding(config);
13803 Roo.KeyMap.prototype = {
13805 * True to stop the event from bubbling and prevent the default browser action if the
13806 * key was handled by the KeyMap (defaults to false)
13812 * Add a new binding to this KeyMap. The following config object properties are supported:
13814 Property Type Description
13815 ---------- --------------- ----------------------------------------------------------------------
13816 key String/Array A single keycode or an array of keycodes to handle
13817 shift Boolean True to handle key only when shift is pressed (defaults to false)
13818 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13819 alt Boolean True to handle key only when alt is pressed (defaults to false)
13820 fn Function The function to call when KeyMap finds the expected key combination
13821 scope Object The scope of the callback function
13827 var map = new Roo.KeyMap(document, {
13828 key: Roo.EventObject.ENTER,
13833 //Add a new binding to the existing KeyMap later
13841 * @param {Object/Array} config A single KeyMap config or an array of configs
13843 addBinding : function(config){
13844 if(config instanceof Array){
13845 for(var i = 0, len = config.length; i < len; i++){
13846 this.addBinding(config[i]);
13850 var keyCode = config.key,
13851 shift = config.shift,
13852 ctrl = config.ctrl,
13855 scope = config.scope;
13856 if(typeof keyCode == "string"){
13858 var keyString = keyCode.toUpperCase();
13859 for(var j = 0, len = keyString.length; j < len; j++){
13860 ks.push(keyString.charCodeAt(j));
13864 var keyArray = keyCode instanceof Array;
13865 var handler = function(e){
13866 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13867 var k = e.getKey();
13869 for(var i = 0, len = keyCode.length; i < len; i++){
13870 if(keyCode[i] == k){
13871 if(this.stopEvent){
13874 fn.call(scope || window, k, e);
13880 if(this.stopEvent){
13883 fn.call(scope || window, k, e);
13888 this.bindings.push(handler);
13892 * Shorthand for adding a single key listener
13893 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13894 * following options:
13895 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13896 * @param {Function} fn The function to call
13897 * @param {Object} scope (optional) The scope of the function
13899 on : function(key, fn, scope){
13900 var keyCode, shift, ctrl, alt;
13901 if(typeof key == "object" && !(key instanceof Array)){
13920 handleKeyDown : function(e){
13921 if(this.enabled){ //just in case
13922 var b = this.bindings;
13923 for(var i = 0, len = b.length; i < len; i++){
13924 b[i].call(this, e);
13930 * Returns true if this KeyMap is enabled
13931 * @return {Boolean}
13933 isEnabled : function(){
13934 return this.enabled;
13938 * Enables this KeyMap
13940 enable: function(){
13942 this.el.on(this.eventName, this.handleKeyDown, this);
13943 this.enabled = true;
13948 * Disable this KeyMap
13950 disable: function(){
13952 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13953 this.enabled = false;
13958 * Ext JS Library 1.1.1
13959 * Copyright(c) 2006-2007, Ext JS, LLC.
13961 * Originally Released Under LGPL - original licence link has changed is not relivant.
13964 * <script type="text/javascript">
13969 * @class Roo.util.TextMetrics
13970 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13971 * wide, in pixels, a given block of text will be.
13974 Roo.util.TextMetrics = function(){
13978 * Measures the size of the specified text
13979 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13980 * that can affect the size of the rendered text
13981 * @param {String} text The text to measure
13982 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13983 * in order to accurately measure the text height
13984 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13986 measure : function(el, text, fixedWidth){
13988 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13991 shared.setFixedWidth(fixedWidth || 'auto');
13992 return shared.getSize(text);
13996 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13997 * the overhead of multiple calls to initialize the style properties on each measurement.
13998 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13999 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14000 * in order to accurately measure the text height
14001 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14003 createInstance : function(el, fixedWidth){
14004 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14011 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14012 var ml = new Roo.Element(document.createElement('div'));
14013 document.body.appendChild(ml.dom);
14014 ml.position('absolute');
14015 ml.setLeftTop(-1000, -1000);
14019 ml.setWidth(fixedWidth);
14024 * Returns the size of the specified text based on the internal element's style and width properties
14025 * @memberOf Roo.util.TextMetrics.Instance#
14026 * @param {String} text The text to measure
14027 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14029 getSize : function(text){
14031 var s = ml.getSize();
14037 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14038 * that can affect the size of the rendered text
14039 * @memberOf Roo.util.TextMetrics.Instance#
14040 * @param {String/HTMLElement} el The element, dom node or id
14042 bind : function(el){
14044 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14049 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14050 * to set a fixed width in order to accurately measure the text height.
14051 * @memberOf Roo.util.TextMetrics.Instance#
14052 * @param {Number} width The width to set on the element
14054 setFixedWidth : function(width){
14055 ml.setWidth(width);
14059 * Returns the measured width of the specified text
14060 * @memberOf Roo.util.TextMetrics.Instance#
14061 * @param {String} text The text to measure
14062 * @return {Number} width The width in pixels
14064 getWidth : function(text){
14065 ml.dom.style.width = 'auto';
14066 return this.getSize(text).width;
14070 * Returns the measured height of the specified text. For multiline text, be sure to call
14071 * {@link #setFixedWidth} if necessary.
14072 * @memberOf Roo.util.TextMetrics.Instance#
14073 * @param {String} text The text to measure
14074 * @return {Number} height The height in pixels
14076 getHeight : function(text){
14077 return this.getSize(text).height;
14081 instance.bind(bindTo);
14086 // backwards compat
14087 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14089 * Ext JS Library 1.1.1
14090 * Copyright(c) 2006-2007, Ext JS, LLC.
14092 * Originally Released Under LGPL - original licence link has changed is not relivant.
14095 * <script type="text/javascript">
14099 * @class Roo.state.Provider
14100 * Abstract base class for state provider implementations. This class provides methods
14101 * for encoding and decoding <b>typed</b> variables including dates and defines the
14102 * Provider interface.
14104 Roo.state.Provider = function(){
14106 * @event statechange
14107 * Fires when a state change occurs.
14108 * @param {Provider} this This state provider
14109 * @param {String} key The state key which was changed
14110 * @param {String} value The encoded value for the state
14113 "statechange": true
14116 Roo.state.Provider.superclass.constructor.call(this);
14118 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14120 * Returns the current value for a key
14121 * @param {String} name The key name
14122 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14123 * @return {Mixed} The state data
14125 get : function(name, defaultValue){
14126 return typeof this.state[name] == "undefined" ?
14127 defaultValue : this.state[name];
14131 * Clears a value from the state
14132 * @param {String} name The key name
14134 clear : function(name){
14135 delete this.state[name];
14136 this.fireEvent("statechange", this, name, null);
14140 * Sets the value for a key
14141 * @param {String} name The key name
14142 * @param {Mixed} value The value to set
14144 set : function(name, value){
14145 this.state[name] = value;
14146 this.fireEvent("statechange", this, name, value);
14150 * Decodes a string previously encoded with {@link #encodeValue}.
14151 * @param {String} value The value to decode
14152 * @return {Mixed} The decoded value
14154 decodeValue : function(cookie){
14155 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14156 var matches = re.exec(unescape(cookie));
14157 if(!matches || !matches[1]) return; // non state cookie
14158 var type = matches[1];
14159 var v = matches[2];
14162 return parseFloat(v);
14164 return new Date(Date.parse(v));
14169 var values = v.split("^");
14170 for(var i = 0, len = values.length; i < len; i++){
14171 all.push(this.decodeValue(values[i]));
14176 var values = v.split("^");
14177 for(var i = 0, len = values.length; i < len; i++){
14178 var kv = values[i].split("=");
14179 all[kv[0]] = this.decodeValue(kv[1]);
14188 * Encodes a value including type information. Decode with {@link #decodeValue}.
14189 * @param {Mixed} value The value to encode
14190 * @return {String} The encoded value
14192 encodeValue : function(v){
14194 if(typeof v == "number"){
14196 }else if(typeof v == "boolean"){
14197 enc = "b:" + (v ? "1" : "0");
14198 }else if(v instanceof Date){
14199 enc = "d:" + v.toGMTString();
14200 }else if(v instanceof Array){
14202 for(var i = 0, len = v.length; i < len; i++){
14203 flat += this.encodeValue(v[i]);
14204 if(i != len-1) flat += "^";
14207 }else if(typeof v == "object"){
14210 if(typeof v[key] != "function"){
14211 flat += key + "=" + this.encodeValue(v[key]) + "^";
14214 enc = "o:" + flat.substring(0, flat.length-1);
14218 return escape(enc);
14224 * Ext JS Library 1.1.1
14225 * Copyright(c) 2006-2007, Ext JS, LLC.
14227 * Originally Released Under LGPL - original licence link has changed is not relivant.
14230 * <script type="text/javascript">
14233 * @class Roo.state.Manager
14234 * This is the global state manager. By default all components that are "state aware" check this class
14235 * for state information if you don't pass them a custom state provider. In order for this class
14236 * to be useful, it must be initialized with a provider when your application initializes.
14238 // in your initialization function
14240 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14242 // supposed you have a {@link Roo.BorderLayout}
14243 var layout = new Roo.BorderLayout(...);
14244 layout.restoreState();
14245 // or a {Roo.BasicDialog}
14246 var dialog = new Roo.BasicDialog(...);
14247 dialog.restoreState();
14251 Roo.state.Manager = function(){
14252 var provider = new Roo.state.Provider();
14256 * Configures the default state provider for your application
14257 * @param {Provider} stateProvider The state provider to set
14259 setProvider : function(stateProvider){
14260 provider = stateProvider;
14264 * Returns the current value for a key
14265 * @param {String} name The key name
14266 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14267 * @return {Mixed} The state data
14269 get : function(key, defaultValue){
14270 return provider.get(key, defaultValue);
14274 * Sets the value for a key
14275 * @param {String} name The key name
14276 * @param {Mixed} value The state data
14278 set : function(key, value){
14279 provider.set(key, value);
14283 * Clears a value from the state
14284 * @param {String} name The key name
14286 clear : function(key){
14287 provider.clear(key);
14291 * Gets the currently configured state provider
14292 * @return {Provider} The state provider
14294 getProvider : function(){
14301 * Ext JS Library 1.1.1
14302 * Copyright(c) 2006-2007, Ext JS, LLC.
14304 * Originally Released Under LGPL - original licence link has changed is not relivant.
14307 * <script type="text/javascript">
14310 * @class Roo.state.CookieProvider
14311 * @extends Roo.state.Provider
14312 * The default Provider implementation which saves state via cookies.
14315 var cp = new Roo.state.CookieProvider({
14317 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14318 domain: "roojs.com"
14320 Roo.state.Manager.setProvider(cp);
14322 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14323 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14324 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14325 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14326 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14327 * domain the page is running on including the 'www' like 'www.roojs.com')
14328 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14330 * Create a new CookieProvider
14331 * @param {Object} config The configuration object
14333 Roo.state.CookieProvider = function(config){
14334 Roo.state.CookieProvider.superclass.constructor.call(this);
14336 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14337 this.domain = null;
14338 this.secure = false;
14339 Roo.apply(this, config);
14340 this.state = this.readCookies();
14343 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14345 set : function(name, value){
14346 if(typeof value == "undefined" || value === null){
14350 this.setCookie(name, value);
14351 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14355 clear : function(name){
14356 this.clearCookie(name);
14357 Roo.state.CookieProvider.superclass.clear.call(this, name);
14361 readCookies : function(){
14363 var c = document.cookie + ";";
14364 var re = /\s?(.*?)=(.*?);/g;
14366 while((matches = re.exec(c)) != null){
14367 var name = matches[1];
14368 var value = matches[2];
14369 if(name && name.substring(0,3) == "ys-"){
14370 cookies[name.substr(3)] = this.decodeValue(value);
14377 setCookie : function(name, value){
14378 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14379 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14380 ((this.path == null) ? "" : ("; path=" + this.path)) +
14381 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14382 ((this.secure == true) ? "; secure" : "");
14386 clearCookie : function(name){
14387 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14388 ((this.path == null) ? "" : ("; path=" + this.path)) +
14389 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14390 ((this.secure == true) ? "; secure" : "");
14394 * Ext JS Library 1.1.1
14395 * Copyright(c) 2006-2007, Ext JS, LLC.
14397 * Originally Released Under LGPL - original licence link has changed is not relivant.
14400 * <script type="text/javascript">
14406 * These classes are derivatives of the similarly named classes in the YUI Library.
14407 * The original license:
14408 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14409 * Code licensed under the BSD License:
14410 * http://developer.yahoo.net/yui/license.txt
14415 var Event=Roo.EventManager;
14416 var Dom=Roo.lib.Dom;
14419 * @class Roo.dd.DragDrop
14420 * @extends Roo.util.Observable
14421 * Defines the interface and base operation of items that that can be
14422 * dragged or can be drop targets. It was designed to be extended, overriding
14423 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14424 * Up to three html elements can be associated with a DragDrop instance:
14426 * <li>linked element: the element that is passed into the constructor.
14427 * This is the element which defines the boundaries for interaction with
14428 * other DragDrop objects.</li>
14429 * <li>handle element(s): The drag operation only occurs if the element that
14430 * was clicked matches a handle element. By default this is the linked
14431 * element, but there are times that you will want only a portion of the
14432 * linked element to initiate the drag operation, and the setHandleElId()
14433 * method provides a way to define this.</li>
14434 * <li>drag element: this represents the element that would be moved along
14435 * with the cursor during a drag operation. By default, this is the linked
14436 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14437 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14440 * This class should not be instantiated until the onload event to ensure that
14441 * the associated elements are available.
14442 * The following would define a DragDrop obj that would interact with any
14443 * other DragDrop obj in the "group1" group:
14445 * dd = new Roo.dd.DragDrop("div1", "group1");
14447 * Since none of the event handlers have been implemented, nothing would
14448 * actually happen if you were to run the code above. Normally you would
14449 * override this class or one of the default implementations, but you can
14450 * also override the methods you want on an instance of the class...
14452 * dd.onDragDrop = function(e, id) {
14453 * alert("dd was dropped on " + id);
14457 * @param {String} id of the element that is linked to this instance
14458 * @param {String} sGroup the group of related DragDrop objects
14459 * @param {object} config an object containing configurable attributes
14460 * Valid properties for DragDrop:
14461 * padding, isTarget, maintainOffset, primaryButtonOnly
14463 Roo.dd.DragDrop = function(id, sGroup, config) {
14465 this.init(id, sGroup, config);
14470 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14473 * The id of the element associated with this object. This is what we
14474 * refer to as the "linked element" because the size and position of
14475 * this element is used to determine when the drag and drop objects have
14483 * Configuration attributes passed into the constructor
14490 * The id of the element that will be dragged. By default this is same
14491 * as the linked element , but could be changed to another element. Ex:
14493 * @property dragElId
14500 * the id of the element that initiates the drag operation. By default
14501 * this is the linked element, but could be changed to be a child of this
14502 * element. This lets us do things like only starting the drag when the
14503 * header element within the linked html element is clicked.
14504 * @property handleElId
14511 * An associative array of HTML tags that will be ignored if clicked.
14512 * @property invalidHandleTypes
14513 * @type {string: string}
14515 invalidHandleTypes: null,
14518 * An associative array of ids for elements that will be ignored if clicked
14519 * @property invalidHandleIds
14520 * @type {string: string}
14522 invalidHandleIds: null,
14525 * An indexted array of css class names for elements that will be ignored
14527 * @property invalidHandleClasses
14530 invalidHandleClasses: null,
14533 * The linked element's absolute X position at the time the drag was
14535 * @property startPageX
14542 * The linked element's absolute X position at the time the drag was
14544 * @property startPageY
14551 * The group defines a logical collection of DragDrop objects that are
14552 * related. Instances only get events when interacting with other
14553 * DragDrop object in the same group. This lets us define multiple
14554 * groups using a single DragDrop subclass if we want.
14556 * @type {string: string}
14561 * Individual drag/drop instances can be locked. This will prevent
14562 * onmousedown start drag.
14570 * Lock this instance
14573 lock: function() { this.locked = true; },
14576 * Unlock this instace
14579 unlock: function() { this.locked = false; },
14582 * By default, all insances can be a drop target. This can be disabled by
14583 * setting isTarget to false.
14590 * The padding configured for this drag and drop object for calculating
14591 * the drop zone intersection with this object.
14598 * Cached reference to the linked element
14599 * @property _domRef
14605 * Internal typeof flag
14606 * @property __ygDragDrop
14609 __ygDragDrop: true,
14612 * Set to true when horizontal contraints are applied
14613 * @property constrainX
14620 * Set to true when vertical contraints are applied
14621 * @property constrainY
14628 * The left constraint
14636 * The right constraint
14644 * The up constraint
14653 * The down constraint
14661 * Maintain offsets when we resetconstraints. Set to true when you want
14662 * the position of the element relative to its parent to stay the same
14663 * when the page changes
14665 * @property maintainOffset
14668 maintainOffset: false,
14671 * Array of pixel locations the element will snap to if we specified a
14672 * horizontal graduation/interval. This array is generated automatically
14673 * when you define a tick interval.
14680 * Array of pixel locations the element will snap to if we specified a
14681 * vertical graduation/interval. This array is generated automatically
14682 * when you define a tick interval.
14689 * By default the drag and drop instance will only respond to the primary
14690 * button click (left button for a right-handed mouse). Set to true to
14691 * allow drag and drop to start with any mouse click that is propogated
14693 * @property primaryButtonOnly
14696 primaryButtonOnly: true,
14699 * The availabe property is false until the linked dom element is accessible.
14700 * @property available
14706 * By default, drags can only be initiated if the mousedown occurs in the
14707 * region the linked element is. This is done in part to work around a
14708 * bug in some browsers that mis-report the mousedown if the previous
14709 * mouseup happened outside of the window. This property is set to true
14710 * if outer handles are defined.
14712 * @property hasOuterHandles
14716 hasOuterHandles: false,
14719 * Code that executes immediately before the startDrag event
14720 * @method b4StartDrag
14723 b4StartDrag: function(x, y) { },
14726 * Abstract method called after a drag/drop object is clicked
14727 * and the drag or mousedown time thresholds have beeen met.
14728 * @method startDrag
14729 * @param {int} X click location
14730 * @param {int} Y click location
14732 startDrag: function(x, y) { /* override this */ },
14735 * Code that executes immediately before the onDrag event
14739 b4Drag: function(e) { },
14742 * Abstract method called during the onMouseMove event while dragging an
14745 * @param {Event} e the mousemove event
14747 onDrag: function(e) { /* override this */ },
14750 * Abstract method called when this element fist begins hovering over
14751 * another DragDrop obj
14752 * @method onDragEnter
14753 * @param {Event} e the mousemove event
14754 * @param {String|DragDrop[]} id In POINT mode, the element
14755 * id this is hovering over. In INTERSECT mode, an array of one or more
14756 * dragdrop items being hovered over.
14758 onDragEnter: function(e, id) { /* override this */ },
14761 * Code that executes immediately before the onDragOver event
14762 * @method b4DragOver
14765 b4DragOver: function(e) { },
14768 * Abstract method called when this element is hovering over another
14770 * @method onDragOver
14771 * @param {Event} e the mousemove event
14772 * @param {String|DragDrop[]} id In POINT mode, the element
14773 * id this is hovering over. In INTERSECT mode, an array of dd items
14774 * being hovered over.
14776 onDragOver: function(e, id) { /* override this */ },
14779 * Code that executes immediately before the onDragOut event
14780 * @method b4DragOut
14783 b4DragOut: function(e) { },
14786 * Abstract method called when we are no longer hovering over an element
14787 * @method onDragOut
14788 * @param {Event} e the mousemove event
14789 * @param {String|DragDrop[]} id In POINT mode, the element
14790 * id this was hovering over. In INTERSECT mode, an array of dd items
14791 * that the mouse is no longer over.
14793 onDragOut: function(e, id) { /* override this */ },
14796 * Code that executes immediately before the onDragDrop event
14797 * @method b4DragDrop
14800 b4DragDrop: function(e) { },
14803 * Abstract method called when this item is dropped on another DragDrop
14805 * @method onDragDrop
14806 * @param {Event} e the mouseup event
14807 * @param {String|DragDrop[]} id In POINT mode, the element
14808 * id this was dropped on. In INTERSECT mode, an array of dd items this
14811 onDragDrop: function(e, id) { /* override this */ },
14814 * Abstract method called when this item is dropped on an area with no
14816 * @method onInvalidDrop
14817 * @param {Event} e the mouseup event
14819 onInvalidDrop: function(e) { /* override this */ },
14822 * Code that executes immediately before the endDrag event
14823 * @method b4EndDrag
14826 b4EndDrag: function(e) { },
14829 * Fired when we are done dragging the object
14831 * @param {Event} e the mouseup event
14833 endDrag: function(e) { /* override this */ },
14836 * Code executed immediately before the onMouseDown event
14837 * @method b4MouseDown
14838 * @param {Event} e the mousedown event
14841 b4MouseDown: function(e) { },
14844 * Event handler that fires when a drag/drop obj gets a mousedown
14845 * @method onMouseDown
14846 * @param {Event} e the mousedown event
14848 onMouseDown: function(e) { /* override this */ },
14851 * Event handler that fires when a drag/drop obj gets a mouseup
14852 * @method onMouseUp
14853 * @param {Event} e the mouseup event
14855 onMouseUp: function(e) { /* override this */ },
14858 * Override the onAvailable method to do what is needed after the initial
14859 * position was determined.
14860 * @method onAvailable
14862 onAvailable: function () {
14866 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14869 defaultPadding : {left:0, right:0, top:0, bottom:0},
14872 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14876 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14877 { dragElId: "existingProxyDiv" });
14878 dd.startDrag = function(){
14879 this.constrainTo("parent-id");
14882 * Or you can initalize it using the {@link Roo.Element} object:
14884 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14885 startDrag : function(){
14886 this.constrainTo("parent-id");
14890 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14891 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14892 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14893 * an object containing the sides to pad. For example: {right:10, bottom:10}
14894 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14896 constrainTo : function(constrainTo, pad, inContent){
14897 if(typeof pad == "number"){
14898 pad = {left: pad, right:pad, top:pad, bottom:pad};
14900 pad = pad || this.defaultPadding;
14901 var b = Roo.get(this.getEl()).getBox();
14902 var ce = Roo.get(constrainTo);
14903 var s = ce.getScroll();
14904 var c, cd = ce.dom;
14905 if(cd == document.body){
14906 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14909 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14913 var topSpace = b.y - c.y;
14914 var leftSpace = b.x - c.x;
14916 this.resetConstraints();
14917 this.setXConstraint(leftSpace - (pad.left||0), // left
14918 c.width - leftSpace - b.width - (pad.right||0) //right
14920 this.setYConstraint(topSpace - (pad.top||0), //top
14921 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14926 * Returns a reference to the linked element
14928 * @return {HTMLElement} the html element
14930 getEl: function() {
14931 if (!this._domRef) {
14932 this._domRef = Roo.getDom(this.id);
14935 return this._domRef;
14939 * Returns a reference to the actual element to drag. By default this is
14940 * the same as the html element, but it can be assigned to another
14941 * element. An example of this can be found in Roo.dd.DDProxy
14942 * @method getDragEl
14943 * @return {HTMLElement} the html element
14945 getDragEl: function() {
14946 return Roo.getDom(this.dragElId);
14950 * Sets up the DragDrop object. Must be called in the constructor of any
14951 * Roo.dd.DragDrop subclass
14953 * @param id the id of the linked element
14954 * @param {String} sGroup the group of related items
14955 * @param {object} config configuration attributes
14957 init: function(id, sGroup, config) {
14958 this.initTarget(id, sGroup, config);
14959 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14960 // Event.on(this.id, "selectstart", Event.preventDefault);
14964 * Initializes Targeting functionality only... the object does not
14965 * get a mousedown handler.
14966 * @method initTarget
14967 * @param id the id of the linked element
14968 * @param {String} sGroup the group of related items
14969 * @param {object} config configuration attributes
14971 initTarget: function(id, sGroup, config) {
14973 // configuration attributes
14974 this.config = config || {};
14976 // create a local reference to the drag and drop manager
14977 this.DDM = Roo.dd.DDM;
14978 // initialize the groups array
14981 // assume that we have an element reference instead of an id if the
14982 // parameter is not a string
14983 if (typeof id !== "string") {
14990 // add to an interaction group
14991 this.addToGroup((sGroup) ? sGroup : "default");
14993 // We don't want to register this as the handle with the manager
14994 // so we just set the id rather than calling the setter.
14995 this.handleElId = id;
14997 // the linked element is the element that gets dragged by default
14998 this.setDragElId(id);
15000 // by default, clicked anchors will not start drag operations.
15001 this.invalidHandleTypes = { A: "A" };
15002 this.invalidHandleIds = {};
15003 this.invalidHandleClasses = [];
15005 this.applyConfig();
15007 this.handleOnAvailable();
15011 * Applies the configuration parameters that were passed into the constructor.
15012 * This is supposed to happen at each level through the inheritance chain. So
15013 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15014 * DragDrop in order to get all of the parameters that are available in
15016 * @method applyConfig
15018 applyConfig: function() {
15020 // configurable properties:
15021 // padding, isTarget, maintainOffset, primaryButtonOnly
15022 this.padding = this.config.padding || [0, 0, 0, 0];
15023 this.isTarget = (this.config.isTarget !== false);
15024 this.maintainOffset = (this.config.maintainOffset);
15025 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15030 * Executed when the linked element is available
15031 * @method handleOnAvailable
15034 handleOnAvailable: function() {
15035 this.available = true;
15036 this.resetConstraints();
15037 this.onAvailable();
15041 * Configures the padding for the target zone in px. Effectively expands
15042 * (or reduces) the virtual object size for targeting calculations.
15043 * Supports css-style shorthand; if only one parameter is passed, all sides
15044 * will have that padding, and if only two are passed, the top and bottom
15045 * will have the first param, the left and right the second.
15046 * @method setPadding
15047 * @param {int} iTop Top pad
15048 * @param {int} iRight Right pad
15049 * @param {int} iBot Bot pad
15050 * @param {int} iLeft Left pad
15052 setPadding: function(iTop, iRight, iBot, iLeft) {
15053 // this.padding = [iLeft, iRight, iTop, iBot];
15054 if (!iRight && 0 !== iRight) {
15055 this.padding = [iTop, iTop, iTop, iTop];
15056 } else if (!iBot && 0 !== iBot) {
15057 this.padding = [iTop, iRight, iTop, iRight];
15059 this.padding = [iTop, iRight, iBot, iLeft];
15064 * Stores the initial placement of the linked element.
15065 * @method setInitialPosition
15066 * @param {int} diffX the X offset, default 0
15067 * @param {int} diffY the Y offset, default 0
15069 setInitPosition: function(diffX, diffY) {
15070 var el = this.getEl();
15072 if (!this.DDM.verifyEl(el)) {
15076 var dx = diffX || 0;
15077 var dy = diffY || 0;
15079 var p = Dom.getXY( el );
15081 this.initPageX = p[0] - dx;
15082 this.initPageY = p[1] - dy;
15084 this.lastPageX = p[0];
15085 this.lastPageY = p[1];
15088 this.setStartPosition(p);
15092 * Sets the start position of the element. This is set when the obj
15093 * is initialized, the reset when a drag is started.
15094 * @method setStartPosition
15095 * @param pos current position (from previous lookup)
15098 setStartPosition: function(pos) {
15099 var p = pos || Dom.getXY( this.getEl() );
15100 this.deltaSetXY = null;
15102 this.startPageX = p[0];
15103 this.startPageY = p[1];
15107 * Add this instance to a group of related drag/drop objects. All
15108 * instances belong to at least one group, and can belong to as many
15109 * groups as needed.
15110 * @method addToGroup
15111 * @param sGroup {string} the name of the group
15113 addToGroup: function(sGroup) {
15114 this.groups[sGroup] = true;
15115 this.DDM.regDragDrop(this, sGroup);
15119 * Remove's this instance from the supplied interaction group
15120 * @method removeFromGroup
15121 * @param {string} sGroup The group to drop
15123 removeFromGroup: function(sGroup) {
15124 if (this.groups[sGroup]) {
15125 delete this.groups[sGroup];
15128 this.DDM.removeDDFromGroup(this, sGroup);
15132 * Allows you to specify that an element other than the linked element
15133 * will be moved with the cursor during a drag
15134 * @method setDragElId
15135 * @param id {string} the id of the element that will be used to initiate the drag
15137 setDragElId: function(id) {
15138 this.dragElId = id;
15142 * Allows you to specify a child of the linked element that should be
15143 * used to initiate the drag operation. An example of this would be if
15144 * you have a content div with text and links. Clicking anywhere in the
15145 * content area would normally start the drag operation. Use this method
15146 * to specify that an element inside of the content div is the element
15147 * that starts the drag operation.
15148 * @method setHandleElId
15149 * @param id {string} the id of the element that will be used to
15150 * initiate the drag.
15152 setHandleElId: function(id) {
15153 if (typeof id !== "string") {
15156 this.handleElId = id;
15157 this.DDM.regHandle(this.id, id);
15161 * Allows you to set an element outside of the linked element as a drag
15163 * @method setOuterHandleElId
15164 * @param id the id of the element that will be used to initiate the drag
15166 setOuterHandleElId: function(id) {
15167 if (typeof id !== "string") {
15170 Event.on(id, "mousedown",
15171 this.handleMouseDown, this);
15172 this.setHandleElId(id);
15174 this.hasOuterHandles = true;
15178 * Remove all drag and drop hooks for this element
15181 unreg: function() {
15182 Event.un(this.id, "mousedown",
15183 this.handleMouseDown);
15184 this._domRef = null;
15185 this.DDM._remove(this);
15188 destroy : function(){
15193 * Returns true if this instance is locked, or the drag drop mgr is locked
15194 * (meaning that all drag/drop is disabled on the page.)
15196 * @return {boolean} true if this obj or all drag/drop is locked, else
15199 isLocked: function() {
15200 return (this.DDM.isLocked() || this.locked);
15204 * Fired when this object is clicked
15205 * @method handleMouseDown
15207 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15210 handleMouseDown: function(e, oDD){
15211 if (this.primaryButtonOnly && e.button != 0) {
15215 if (this.isLocked()) {
15219 this.DDM.refreshCache(this.groups);
15221 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15222 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15224 if (this.clickValidator(e)) {
15226 // set the initial element position
15227 this.setStartPosition();
15230 this.b4MouseDown(e);
15231 this.onMouseDown(e);
15233 this.DDM.handleMouseDown(e, this);
15235 this.DDM.stopEvent(e);
15243 clickValidator: function(e) {
15244 var target = e.getTarget();
15245 return ( this.isValidHandleChild(target) &&
15246 (this.id == this.handleElId ||
15247 this.DDM.handleWasClicked(target, this.id)) );
15251 * Allows you to specify a tag name that should not start a drag operation
15252 * when clicked. This is designed to facilitate embedding links within a
15253 * drag handle that do something other than start the drag.
15254 * @method addInvalidHandleType
15255 * @param {string} tagName the type of element to exclude
15257 addInvalidHandleType: function(tagName) {
15258 var type = tagName.toUpperCase();
15259 this.invalidHandleTypes[type] = type;
15263 * Lets you to specify an element id for a child of a drag handle
15264 * that should not initiate a drag
15265 * @method addInvalidHandleId
15266 * @param {string} id the element id of the element you wish to ignore
15268 addInvalidHandleId: function(id) {
15269 if (typeof id !== "string") {
15272 this.invalidHandleIds[id] = id;
15276 * Lets you specify a css class of elements that will not initiate a drag
15277 * @method addInvalidHandleClass
15278 * @param {string} cssClass the class of the elements you wish to ignore
15280 addInvalidHandleClass: function(cssClass) {
15281 this.invalidHandleClasses.push(cssClass);
15285 * Unsets an excluded tag name set by addInvalidHandleType
15286 * @method removeInvalidHandleType
15287 * @param {string} tagName the type of element to unexclude
15289 removeInvalidHandleType: function(tagName) {
15290 var type = tagName.toUpperCase();
15291 // this.invalidHandleTypes[type] = null;
15292 delete this.invalidHandleTypes[type];
15296 * Unsets an invalid handle id
15297 * @method removeInvalidHandleId
15298 * @param {string} id the id of the element to re-enable
15300 removeInvalidHandleId: function(id) {
15301 if (typeof id !== "string") {
15304 delete this.invalidHandleIds[id];
15308 * Unsets an invalid css class
15309 * @method removeInvalidHandleClass
15310 * @param {string} cssClass the class of the element(s) you wish to
15313 removeInvalidHandleClass: function(cssClass) {
15314 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15315 if (this.invalidHandleClasses[i] == cssClass) {
15316 delete this.invalidHandleClasses[i];
15322 * Checks the tag exclusion list to see if this click should be ignored
15323 * @method isValidHandleChild
15324 * @param {HTMLElement} node the HTMLElement to evaluate
15325 * @return {boolean} true if this is a valid tag type, false if not
15327 isValidHandleChild: function(node) {
15330 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15333 nodeName = node.nodeName.toUpperCase();
15335 nodeName = node.nodeName;
15337 valid = valid && !this.invalidHandleTypes[nodeName];
15338 valid = valid && !this.invalidHandleIds[node.id];
15340 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15341 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15350 * Create the array of horizontal tick marks if an interval was specified
15351 * in setXConstraint().
15352 * @method setXTicks
15355 setXTicks: function(iStartX, iTickSize) {
15357 this.xTickSize = iTickSize;
15361 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15363 this.xTicks[this.xTicks.length] = i;
15368 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15370 this.xTicks[this.xTicks.length] = i;
15375 this.xTicks.sort(this.DDM.numericSort) ;
15379 * Create the array of vertical tick marks if an interval was specified in
15380 * setYConstraint().
15381 * @method setYTicks
15384 setYTicks: function(iStartY, iTickSize) {
15386 this.yTickSize = iTickSize;
15390 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15392 this.yTicks[this.yTicks.length] = i;
15397 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15399 this.yTicks[this.yTicks.length] = i;
15404 this.yTicks.sort(this.DDM.numericSort) ;
15408 * By default, the element can be dragged any place on the screen. Use
15409 * this method to limit the horizontal travel of the element. Pass in
15410 * 0,0 for the parameters if you want to lock the drag to the y axis.
15411 * @method setXConstraint
15412 * @param {int} iLeft the number of pixels the element can move to the left
15413 * @param {int} iRight the number of pixels the element can move to the
15415 * @param {int} iTickSize optional parameter for specifying that the
15417 * should move iTickSize pixels at a time.
15419 setXConstraint: function(iLeft, iRight, iTickSize) {
15420 this.leftConstraint = iLeft;
15421 this.rightConstraint = iRight;
15423 this.minX = this.initPageX - iLeft;
15424 this.maxX = this.initPageX + iRight;
15425 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15427 this.constrainX = true;
15431 * Clears any constraints applied to this instance. Also clears ticks
15432 * since they can't exist independent of a constraint at this time.
15433 * @method clearConstraints
15435 clearConstraints: function() {
15436 this.constrainX = false;
15437 this.constrainY = false;
15442 * Clears any tick interval defined for this instance
15443 * @method clearTicks
15445 clearTicks: function() {
15446 this.xTicks = null;
15447 this.yTicks = null;
15448 this.xTickSize = 0;
15449 this.yTickSize = 0;
15453 * By default, the element can be dragged any place on the screen. Set
15454 * this to limit the vertical travel of the element. Pass in 0,0 for the
15455 * parameters if you want to lock the drag to the x axis.
15456 * @method setYConstraint
15457 * @param {int} iUp the number of pixels the element can move up
15458 * @param {int} iDown the number of pixels the element can move down
15459 * @param {int} iTickSize optional parameter for specifying that the
15460 * element should move iTickSize pixels at a time.
15462 setYConstraint: function(iUp, iDown, iTickSize) {
15463 this.topConstraint = iUp;
15464 this.bottomConstraint = iDown;
15466 this.minY = this.initPageY - iUp;
15467 this.maxY = this.initPageY + iDown;
15468 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15470 this.constrainY = true;
15475 * resetConstraints must be called if you manually reposition a dd element.
15476 * @method resetConstraints
15477 * @param {boolean} maintainOffset
15479 resetConstraints: function() {
15482 // Maintain offsets if necessary
15483 if (this.initPageX || this.initPageX === 0) {
15484 // figure out how much this thing has moved
15485 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15486 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15488 this.setInitPosition(dx, dy);
15490 // This is the first time we have detected the element's position
15492 this.setInitPosition();
15495 if (this.constrainX) {
15496 this.setXConstraint( this.leftConstraint,
15497 this.rightConstraint,
15501 if (this.constrainY) {
15502 this.setYConstraint( this.topConstraint,
15503 this.bottomConstraint,
15509 * Normally the drag element is moved pixel by pixel, but we can specify
15510 * that it move a number of pixels at a time. This method resolves the
15511 * location when we have it set up like this.
15513 * @param {int} val where we want to place the object
15514 * @param {int[]} tickArray sorted array of valid points
15515 * @return {int} the closest tick
15518 getTick: function(val, tickArray) {
15521 // If tick interval is not defined, it is effectively 1 pixel,
15522 // so we return the value passed to us.
15524 } else if (tickArray[0] >= val) {
15525 // The value is lower than the first tick, so we return the first
15527 return tickArray[0];
15529 for (var i=0, len=tickArray.length; i<len; ++i) {
15531 if (tickArray[next] && tickArray[next] >= val) {
15532 var diff1 = val - tickArray[i];
15533 var diff2 = tickArray[next] - val;
15534 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15538 // The value is larger than the last tick, so we return the last
15540 return tickArray[tickArray.length - 1];
15547 * @return {string} string representation of the dd obj
15549 toString: function() {
15550 return ("DragDrop " + this.id);
15558 * Ext JS Library 1.1.1
15559 * Copyright(c) 2006-2007, Ext JS, LLC.
15561 * Originally Released Under LGPL - original licence link has changed is not relivant.
15564 * <script type="text/javascript">
15569 * The drag and drop utility provides a framework for building drag and drop
15570 * applications. In addition to enabling drag and drop for specific elements,
15571 * the drag and drop elements are tracked by the manager class, and the
15572 * interactions between the various elements are tracked during the drag and
15573 * the implementing code is notified about these important moments.
15576 // Only load the library once. Rewriting the manager class would orphan
15577 // existing drag and drop instances.
15578 if (!Roo.dd.DragDropMgr) {
15581 * @class Roo.dd.DragDropMgr
15582 * DragDropMgr is a singleton that tracks the element interaction for
15583 * all DragDrop items in the window. Generally, you will not call
15584 * this class directly, but it does have helper methods that could
15585 * be useful in your DragDrop implementations.
15588 Roo.dd.DragDropMgr = function() {
15590 var Event = Roo.EventManager;
15595 * Two dimensional Array of registered DragDrop objects. The first
15596 * dimension is the DragDrop item group, the second the DragDrop
15599 * @type {string: string}
15606 * Array of element ids defined as drag handles. Used to determine
15607 * if the element that generated the mousedown event is actually the
15608 * handle and not the html element itself.
15609 * @property handleIds
15610 * @type {string: string}
15617 * the DragDrop object that is currently being dragged
15618 * @property dragCurrent
15626 * the DragDrop object(s) that are being hovered over
15627 * @property dragOvers
15635 * the X distance between the cursor and the object being dragged
15644 * the Y distance between the cursor and the object being dragged
15653 * Flag to determine if we should prevent the default behavior of the
15654 * events we define. By default this is true, but this can be set to
15655 * false if you need the default behavior (not recommended)
15656 * @property preventDefault
15660 preventDefault: true,
15663 * Flag to determine if we should stop the propagation of the events
15664 * we generate. This is true by default but you may want to set it to
15665 * false if the html element contains other features that require the
15667 * @property stopPropagation
15671 stopPropagation: true,
15674 * Internal flag that is set to true when drag and drop has been
15676 * @property initialized
15683 * All drag and drop can be disabled.
15691 * Called the first time an element is registered.
15697 this.initialized = true;
15701 * In point mode, drag and drop interaction is defined by the
15702 * location of the cursor during the drag/drop
15710 * In intersect mode, drag and drop interactio nis defined by the
15711 * overlap of two or more drag and drop objects.
15712 * @property INTERSECT
15719 * The current drag and drop mode. Default: POINT
15727 * Runs method on all drag and drop objects
15728 * @method _execOnAll
15732 _execOnAll: function(sMethod, args) {
15733 for (var i in this.ids) {
15734 for (var j in this.ids[i]) {
15735 var oDD = this.ids[i][j];
15736 if (! this.isTypeOfDD(oDD)) {
15739 oDD[sMethod].apply(oDD, args);
15745 * Drag and drop initialization. Sets up the global event handlers
15750 _onLoad: function() {
15755 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15756 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15757 Event.on(window, "unload", this._onUnload, this, true);
15758 Event.on(window, "resize", this._onResize, this, true);
15759 // Event.on(window, "mouseout", this._test);
15764 * Reset constraints on all drag and drop objs
15765 * @method _onResize
15769 _onResize: function(e) {
15770 this._execOnAll("resetConstraints", []);
15774 * Lock all drag and drop functionality
15778 lock: function() { this.locked = true; },
15781 * Unlock all drag and drop functionality
15785 unlock: function() { this.locked = false; },
15788 * Is drag and drop locked?
15790 * @return {boolean} True if drag and drop is locked, false otherwise.
15793 isLocked: function() { return this.locked; },
15796 * Location cache that is set for all drag drop objects when a drag is
15797 * initiated, cleared when the drag is finished.
15798 * @property locationCache
15805 * Set useCache to false if you want to force object the lookup of each
15806 * drag and drop linked element constantly during a drag.
15807 * @property useCache
15814 * The number of pixels that the mouse needs to move after the
15815 * mousedown before the drag is initiated. Default=3;
15816 * @property clickPixelThresh
15820 clickPixelThresh: 3,
15823 * The number of milliseconds after the mousedown event to initiate the
15824 * drag if we don't get a mouseup event. Default=1000
15825 * @property clickTimeThresh
15829 clickTimeThresh: 350,
15832 * Flag that indicates that either the drag pixel threshold or the
15833 * mousdown time threshold has been met
15834 * @property dragThreshMet
15839 dragThreshMet: false,
15842 * Timeout used for the click time threshold
15843 * @property clickTimeout
15848 clickTimeout: null,
15851 * The X position of the mousedown event stored for later use when a
15852 * drag threshold is met.
15861 * The Y position of the mousedown event stored for later use when a
15862 * drag threshold is met.
15871 * Each DragDrop instance must be registered with the DragDropMgr.
15872 * This is executed in DragDrop.init()
15873 * @method regDragDrop
15874 * @param {DragDrop} oDD the DragDrop object to register
15875 * @param {String} sGroup the name of the group this element belongs to
15878 regDragDrop: function(oDD, sGroup) {
15879 if (!this.initialized) { this.init(); }
15881 if (!this.ids[sGroup]) {
15882 this.ids[sGroup] = {};
15884 this.ids[sGroup][oDD.id] = oDD;
15888 * Removes the supplied dd instance from the supplied group. Executed
15889 * by DragDrop.removeFromGroup, so don't call this function directly.
15890 * @method removeDDFromGroup
15894 removeDDFromGroup: function(oDD, sGroup) {
15895 if (!this.ids[sGroup]) {
15896 this.ids[sGroup] = {};
15899 var obj = this.ids[sGroup];
15900 if (obj && obj[oDD.id]) {
15901 delete obj[oDD.id];
15906 * Unregisters a drag and drop item. This is executed in
15907 * DragDrop.unreg, use that method instead of calling this directly.
15912 _remove: function(oDD) {
15913 for (var g in oDD.groups) {
15914 if (g && this.ids[g][oDD.id]) {
15915 delete this.ids[g][oDD.id];
15918 delete this.handleIds[oDD.id];
15922 * Each DragDrop handle element must be registered. This is done
15923 * automatically when executing DragDrop.setHandleElId()
15924 * @method regHandle
15925 * @param {String} sDDId the DragDrop id this element is a handle for
15926 * @param {String} sHandleId the id of the element that is the drag
15930 regHandle: function(sDDId, sHandleId) {
15931 if (!this.handleIds[sDDId]) {
15932 this.handleIds[sDDId] = {};
15934 this.handleIds[sDDId][sHandleId] = sHandleId;
15938 * Utility function to determine if a given element has been
15939 * registered as a drag drop item.
15940 * @method isDragDrop
15941 * @param {String} id the element id to check
15942 * @return {boolean} true if this element is a DragDrop item,
15946 isDragDrop: function(id) {
15947 return ( this.getDDById(id) ) ? true : false;
15951 * Returns the drag and drop instances that are in all groups the
15952 * passed in instance belongs to.
15953 * @method getRelated
15954 * @param {DragDrop} p_oDD the obj to get related data for
15955 * @param {boolean} bTargetsOnly if true, only return targetable objs
15956 * @return {DragDrop[]} the related instances
15959 getRelated: function(p_oDD, bTargetsOnly) {
15961 for (var i in p_oDD.groups) {
15962 for (j in this.ids[i]) {
15963 var dd = this.ids[i][j];
15964 if (! this.isTypeOfDD(dd)) {
15967 if (!bTargetsOnly || dd.isTarget) {
15968 oDDs[oDDs.length] = dd;
15977 * Returns true if the specified dd target is a legal target for
15978 * the specifice drag obj
15979 * @method isLegalTarget
15980 * @param {DragDrop} the drag obj
15981 * @param {DragDrop} the target
15982 * @return {boolean} true if the target is a legal target for the
15986 isLegalTarget: function (oDD, oTargetDD) {
15987 var targets = this.getRelated(oDD, true);
15988 for (var i=0, len=targets.length;i<len;++i) {
15989 if (targets[i].id == oTargetDD.id) {
15998 * My goal is to be able to transparently determine if an object is
15999 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16000 * returns "object", oDD.constructor.toString() always returns
16001 * "DragDrop" and not the name of the subclass. So for now it just
16002 * evaluates a well-known variable in DragDrop.
16003 * @method isTypeOfDD
16004 * @param {Object} the object to evaluate
16005 * @return {boolean} true if typeof oDD = DragDrop
16008 isTypeOfDD: function (oDD) {
16009 return (oDD && oDD.__ygDragDrop);
16013 * Utility function to determine if a given element has been
16014 * registered as a drag drop handle for the given Drag Drop object.
16016 * @param {String} id the element id to check
16017 * @return {boolean} true if this element is a DragDrop handle, false
16021 isHandle: function(sDDId, sHandleId) {
16022 return ( this.handleIds[sDDId] &&
16023 this.handleIds[sDDId][sHandleId] );
16027 * Returns the DragDrop instance for a given id
16028 * @method getDDById
16029 * @param {String} id the id of the DragDrop object
16030 * @return {DragDrop} the drag drop object, null if it is not found
16033 getDDById: function(id) {
16034 for (var i in this.ids) {
16035 if (this.ids[i][id]) {
16036 return this.ids[i][id];
16043 * Fired after a registered DragDrop object gets the mousedown event.
16044 * Sets up the events required to track the object being dragged
16045 * @method handleMouseDown
16046 * @param {Event} e the event
16047 * @param oDD the DragDrop object being dragged
16051 handleMouseDown: function(e, oDD) {
16053 Roo.QuickTips.disable();
16055 this.currentTarget = e.getTarget();
16057 this.dragCurrent = oDD;
16059 var el = oDD.getEl();
16061 // track start position
16062 this.startX = e.getPageX();
16063 this.startY = e.getPageY();
16065 this.deltaX = this.startX - el.offsetLeft;
16066 this.deltaY = this.startY - el.offsetTop;
16068 this.dragThreshMet = false;
16070 this.clickTimeout = setTimeout(
16072 var DDM = Roo.dd.DDM;
16073 DDM.startDrag(DDM.startX, DDM.startY);
16075 this.clickTimeThresh );
16079 * Fired when either the drag pixel threshol or the mousedown hold
16080 * time threshold has been met.
16081 * @method startDrag
16082 * @param x {int} the X position of the original mousedown
16083 * @param y {int} the Y position of the original mousedown
16086 startDrag: function(x, y) {
16087 clearTimeout(this.clickTimeout);
16088 if (this.dragCurrent) {
16089 this.dragCurrent.b4StartDrag(x, y);
16090 this.dragCurrent.startDrag(x, y);
16092 this.dragThreshMet = true;
16096 * Internal function to handle the mouseup event. Will be invoked
16097 * from the context of the document.
16098 * @method handleMouseUp
16099 * @param {Event} e the event
16103 handleMouseUp: function(e) {
16106 Roo.QuickTips.enable();
16108 if (! this.dragCurrent) {
16112 clearTimeout(this.clickTimeout);
16114 if (this.dragThreshMet) {
16115 this.fireEvents(e, true);
16125 * Utility to stop event propagation and event default, if these
16126 * features are turned on.
16127 * @method stopEvent
16128 * @param {Event} e the event as returned by this.getEvent()
16131 stopEvent: function(e){
16132 if(this.stopPropagation) {
16133 e.stopPropagation();
16136 if (this.preventDefault) {
16137 e.preventDefault();
16142 * Internal function to clean up event handlers after the drag
16143 * operation is complete
16145 * @param {Event} e the event
16149 stopDrag: function(e) {
16150 // Fire the drag end event for the item that was dragged
16151 if (this.dragCurrent) {
16152 if (this.dragThreshMet) {
16153 this.dragCurrent.b4EndDrag(e);
16154 this.dragCurrent.endDrag(e);
16157 this.dragCurrent.onMouseUp(e);
16160 this.dragCurrent = null;
16161 this.dragOvers = {};
16165 * Internal function to handle the mousemove event. Will be invoked
16166 * from the context of the html element.
16168 * @TODO figure out what we can do about mouse events lost when the
16169 * user drags objects beyond the window boundary. Currently we can
16170 * detect this in internet explorer by verifying that the mouse is
16171 * down during the mousemove event. Firefox doesn't give us the
16172 * button state on the mousemove event.
16173 * @method handleMouseMove
16174 * @param {Event} e the event
16178 handleMouseMove: function(e) {
16179 if (! this.dragCurrent) {
16183 // var button = e.which || e.button;
16185 // check for IE mouseup outside of page boundary
16186 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16188 return this.handleMouseUp(e);
16191 if (!this.dragThreshMet) {
16192 var diffX = Math.abs(this.startX - e.getPageX());
16193 var diffY = Math.abs(this.startY - e.getPageY());
16194 if (diffX > this.clickPixelThresh ||
16195 diffY > this.clickPixelThresh) {
16196 this.startDrag(this.startX, this.startY);
16200 if (this.dragThreshMet) {
16201 this.dragCurrent.b4Drag(e);
16202 this.dragCurrent.onDrag(e);
16203 if(!this.dragCurrent.moveOnly){
16204 this.fireEvents(e, false);
16214 * Iterates over all of the DragDrop elements to find ones we are
16215 * hovering over or dropping on
16216 * @method fireEvents
16217 * @param {Event} e the event
16218 * @param {boolean} isDrop is this a drop op or a mouseover op?
16222 fireEvents: function(e, isDrop) {
16223 var dc = this.dragCurrent;
16225 // If the user did the mouse up outside of the window, we could
16226 // get here even though we have ended the drag.
16227 if (!dc || dc.isLocked()) {
16231 var pt = e.getPoint();
16233 // cache the previous dragOver array
16239 var enterEvts = [];
16241 // Check to see if the object(s) we were hovering over is no longer
16242 // being hovered over so we can fire the onDragOut event
16243 for (var i in this.dragOvers) {
16245 var ddo = this.dragOvers[i];
16247 if (! this.isTypeOfDD(ddo)) {
16251 if (! this.isOverTarget(pt, ddo, this.mode)) {
16252 outEvts.push( ddo );
16255 oldOvers[i] = true;
16256 delete this.dragOvers[i];
16259 for (var sGroup in dc.groups) {
16261 if ("string" != typeof sGroup) {
16265 for (i in this.ids[sGroup]) {
16266 var oDD = this.ids[sGroup][i];
16267 if (! this.isTypeOfDD(oDD)) {
16271 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16272 if (this.isOverTarget(pt, oDD, this.mode)) {
16273 // look for drop interactions
16275 dropEvts.push( oDD );
16276 // look for drag enter and drag over interactions
16279 // initial drag over: dragEnter fires
16280 if (!oldOvers[oDD.id]) {
16281 enterEvts.push( oDD );
16282 // subsequent drag overs: dragOver fires
16284 overEvts.push( oDD );
16287 this.dragOvers[oDD.id] = oDD;
16295 if (outEvts.length) {
16296 dc.b4DragOut(e, outEvts);
16297 dc.onDragOut(e, outEvts);
16300 if (enterEvts.length) {
16301 dc.onDragEnter(e, enterEvts);
16304 if (overEvts.length) {
16305 dc.b4DragOver(e, overEvts);
16306 dc.onDragOver(e, overEvts);
16309 if (dropEvts.length) {
16310 dc.b4DragDrop(e, dropEvts);
16311 dc.onDragDrop(e, dropEvts);
16315 // fire dragout events
16317 for (i=0, len=outEvts.length; i<len; ++i) {
16318 dc.b4DragOut(e, outEvts[i].id);
16319 dc.onDragOut(e, outEvts[i].id);
16322 // fire enter events
16323 for (i=0,len=enterEvts.length; i<len; ++i) {
16324 // dc.b4DragEnter(e, oDD.id);
16325 dc.onDragEnter(e, enterEvts[i].id);
16328 // fire over events
16329 for (i=0,len=overEvts.length; i<len; ++i) {
16330 dc.b4DragOver(e, overEvts[i].id);
16331 dc.onDragOver(e, overEvts[i].id);
16334 // fire drop events
16335 for (i=0, len=dropEvts.length; i<len; ++i) {
16336 dc.b4DragDrop(e, dropEvts[i].id);
16337 dc.onDragDrop(e, dropEvts[i].id);
16342 // notify about a drop that did not find a target
16343 if (isDrop && !dropEvts.length) {
16344 dc.onInvalidDrop(e);
16350 * Helper function for getting the best match from the list of drag
16351 * and drop objects returned by the drag and drop events when we are
16352 * in INTERSECT mode. It returns either the first object that the
16353 * cursor is over, or the object that has the greatest overlap with
16354 * the dragged element.
16355 * @method getBestMatch
16356 * @param {DragDrop[]} dds The array of drag and drop objects
16358 * @return {DragDrop} The best single match
16361 getBestMatch: function(dds) {
16363 // Return null if the input is not what we expect
16364 //if (!dds || !dds.length || dds.length == 0) {
16366 // If there is only one item, it wins
16367 //} else if (dds.length == 1) {
16369 var len = dds.length;
16374 // Loop through the targeted items
16375 for (var i=0; i<len; ++i) {
16377 // If the cursor is over the object, it wins. If the
16378 // cursor is over multiple matches, the first one we come
16380 if (dd.cursorIsOver) {
16383 // Otherwise the object with the most overlap wins
16386 winner.overlap.getArea() < dd.overlap.getArea()) {
16397 * Refreshes the cache of the top-left and bottom-right points of the
16398 * drag and drop objects in the specified group(s). This is in the
16399 * format that is stored in the drag and drop instance, so typical
16402 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16406 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16408 * @TODO this really should be an indexed array. Alternatively this
16409 * method could accept both.
16410 * @method refreshCache
16411 * @param {Object} groups an associative array of groups to refresh
16414 refreshCache: function(groups) {
16415 for (var sGroup in groups) {
16416 if ("string" != typeof sGroup) {
16419 for (var i in this.ids[sGroup]) {
16420 var oDD = this.ids[sGroup][i];
16422 if (this.isTypeOfDD(oDD)) {
16423 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16424 var loc = this.getLocation(oDD);
16426 this.locationCache[oDD.id] = loc;
16428 delete this.locationCache[oDD.id];
16429 // this will unregister the drag and drop object if
16430 // the element is not in a usable state
16439 * This checks to make sure an element exists and is in the DOM. The
16440 * main purpose is to handle cases where innerHTML is used to remove
16441 * drag and drop objects from the DOM. IE provides an 'unspecified
16442 * error' when trying to access the offsetParent of such an element
16444 * @param {HTMLElement} el the element to check
16445 * @return {boolean} true if the element looks usable
16448 verifyEl: function(el) {
16453 parent = el.offsetParent;
16456 parent = el.offsetParent;
16467 * Returns a Region object containing the drag and drop element's position
16468 * and size, including the padding configured for it
16469 * @method getLocation
16470 * @param {DragDrop} oDD the drag and drop object to get the
16472 * @return {Roo.lib.Region} a Region object representing the total area
16473 * the element occupies, including any padding
16474 * the instance is configured for.
16477 getLocation: function(oDD) {
16478 if (! this.isTypeOfDD(oDD)) {
16482 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16485 pos= Roo.lib.Dom.getXY(el);
16493 x2 = x1 + el.offsetWidth;
16495 y2 = y1 + el.offsetHeight;
16497 t = y1 - oDD.padding[0];
16498 r = x2 + oDD.padding[1];
16499 b = y2 + oDD.padding[2];
16500 l = x1 - oDD.padding[3];
16502 return new Roo.lib.Region( t, r, b, l );
16506 * Checks the cursor location to see if it over the target
16507 * @method isOverTarget
16508 * @param {Roo.lib.Point} pt The point to evaluate
16509 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16510 * @return {boolean} true if the mouse is over the target
16514 isOverTarget: function(pt, oTarget, intersect) {
16515 // use cache if available
16516 var loc = this.locationCache[oTarget.id];
16517 if (!loc || !this.useCache) {
16518 loc = this.getLocation(oTarget);
16519 this.locationCache[oTarget.id] = loc;
16527 oTarget.cursorIsOver = loc.contains( pt );
16529 // DragDrop is using this as a sanity check for the initial mousedown
16530 // in this case we are done. In POINT mode, if the drag obj has no
16531 // contraints, we are also done. Otherwise we need to evaluate the
16532 // location of the target as related to the actual location of the
16533 // dragged element.
16534 var dc = this.dragCurrent;
16535 if (!dc || !dc.getTargetCoord ||
16536 (!intersect && !dc.constrainX && !dc.constrainY)) {
16537 return oTarget.cursorIsOver;
16540 oTarget.overlap = null;
16542 // Get the current location of the drag element, this is the
16543 // location of the mouse event less the delta that represents
16544 // where the original mousedown happened on the element. We
16545 // need to consider constraints and ticks as well.
16546 var pos = dc.getTargetCoord(pt.x, pt.y);
16548 var el = dc.getDragEl();
16549 var curRegion = new Roo.lib.Region( pos.y,
16550 pos.x + el.offsetWidth,
16551 pos.y + el.offsetHeight,
16554 var overlap = curRegion.intersect(loc);
16557 oTarget.overlap = overlap;
16558 return (intersect) ? true : oTarget.cursorIsOver;
16565 * unload event handler
16566 * @method _onUnload
16570 _onUnload: function(e, me) {
16571 Roo.dd.DragDropMgr.unregAll();
16575 * Cleans up the drag and drop events and objects.
16580 unregAll: function() {
16582 if (this.dragCurrent) {
16584 this.dragCurrent = null;
16587 this._execOnAll("unreg", []);
16589 for (i in this.elementCache) {
16590 delete this.elementCache[i];
16593 this.elementCache = {};
16598 * A cache of DOM elements
16599 * @property elementCache
16606 * Get the wrapper for the DOM element specified
16607 * @method getElWrapper
16608 * @param {String} id the id of the element to get
16609 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16611 * @deprecated This wrapper isn't that useful
16614 getElWrapper: function(id) {
16615 var oWrapper = this.elementCache[id];
16616 if (!oWrapper || !oWrapper.el) {
16617 oWrapper = this.elementCache[id] =
16618 new this.ElementWrapper(Roo.getDom(id));
16624 * Returns the actual DOM element
16625 * @method getElement
16626 * @param {String} id the id of the elment to get
16627 * @return {Object} The element
16628 * @deprecated use Roo.getDom instead
16631 getElement: function(id) {
16632 return Roo.getDom(id);
16636 * Returns the style property for the DOM element (i.e.,
16637 * document.getElById(id).style)
16639 * @param {String} id the id of the elment to get
16640 * @return {Object} The style property of the element
16641 * @deprecated use Roo.getDom instead
16644 getCss: function(id) {
16645 var el = Roo.getDom(id);
16646 return (el) ? el.style : null;
16650 * Inner class for cached elements
16651 * @class DragDropMgr.ElementWrapper
16656 ElementWrapper: function(el) {
16661 this.el = el || null;
16666 this.id = this.el && el.id;
16668 * A reference to the style property
16671 this.css = this.el && el.style;
16675 * Returns the X position of an html element
16677 * @param el the element for which to get the position
16678 * @return {int} the X coordinate
16680 * @deprecated use Roo.lib.Dom.getX instead
16683 getPosX: function(el) {
16684 return Roo.lib.Dom.getX(el);
16688 * Returns the Y position of an html element
16690 * @param el the element for which to get the position
16691 * @return {int} the Y coordinate
16692 * @deprecated use Roo.lib.Dom.getY instead
16695 getPosY: function(el) {
16696 return Roo.lib.Dom.getY(el);
16700 * Swap two nodes. In IE, we use the native method, for others we
16701 * emulate the IE behavior
16703 * @param n1 the first node to swap
16704 * @param n2 the other node to swap
16707 swapNode: function(n1, n2) {
16711 var p = n2.parentNode;
16712 var s = n2.nextSibling;
16715 p.insertBefore(n1, n2);
16716 } else if (n2 == n1.nextSibling) {
16717 p.insertBefore(n2, n1);
16719 n1.parentNode.replaceChild(n2, n1);
16720 p.insertBefore(n1, s);
16726 * Returns the current scroll position
16727 * @method getScroll
16731 getScroll: function () {
16732 var t, l, dde=document.documentElement, db=document.body;
16733 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16735 l = dde.scrollLeft;
16742 return { top: t, left: l };
16746 * Returns the specified element style property
16748 * @param {HTMLElement} el the element
16749 * @param {string} styleProp the style property
16750 * @return {string} The value of the style property
16751 * @deprecated use Roo.lib.Dom.getStyle
16754 getStyle: function(el, styleProp) {
16755 return Roo.fly(el).getStyle(styleProp);
16759 * Gets the scrollTop
16760 * @method getScrollTop
16761 * @return {int} the document's scrollTop
16764 getScrollTop: function () { return this.getScroll().top; },
16767 * Gets the scrollLeft
16768 * @method getScrollLeft
16769 * @return {int} the document's scrollTop
16772 getScrollLeft: function () { return this.getScroll().left; },
16775 * Sets the x/y position of an element to the location of the
16778 * @param {HTMLElement} moveEl The element to move
16779 * @param {HTMLElement} targetEl The position reference element
16782 moveToEl: function (moveEl, targetEl) {
16783 var aCoord = Roo.lib.Dom.getXY(targetEl);
16784 Roo.lib.Dom.setXY(moveEl, aCoord);
16788 * Numeric array sort function
16789 * @method numericSort
16792 numericSort: function(a, b) { return (a - b); },
16796 * @property _timeoutCount
16803 * Trying to make the load order less important. Without this we get
16804 * an error if this file is loaded before the Event Utility.
16805 * @method _addListeners
16809 _addListeners: function() {
16810 var DDM = Roo.dd.DDM;
16811 if ( Roo.lib.Event && document ) {
16814 if (DDM._timeoutCount > 2000) {
16816 setTimeout(DDM._addListeners, 10);
16817 if (document && document.body) {
16818 DDM._timeoutCount += 1;
16825 * Recursively searches the immediate parent and all child nodes for
16826 * the handle element in order to determine wheter or not it was
16828 * @method handleWasClicked
16829 * @param node the html element to inspect
16832 handleWasClicked: function(node, id) {
16833 if (this.isHandle(id, node.id)) {
16836 // check to see if this is a text node child of the one we want
16837 var p = node.parentNode;
16840 if (this.isHandle(id, p.id)) {
16855 // shorter alias, save a few bytes
16856 Roo.dd.DDM = Roo.dd.DragDropMgr;
16857 Roo.dd.DDM._addListeners();
16861 * Ext JS Library 1.1.1
16862 * Copyright(c) 2006-2007, Ext JS, LLC.
16864 * Originally Released Under LGPL - original licence link has changed is not relivant.
16867 * <script type="text/javascript">
16872 * A DragDrop implementation where the linked element follows the
16873 * mouse cursor during a drag.
16874 * @extends Roo.dd.DragDrop
16876 * @param {String} id the id of the linked element
16877 * @param {String} sGroup the group of related DragDrop items
16878 * @param {object} config an object containing configurable attributes
16879 * Valid properties for DD:
16882 Roo.dd.DD = function(id, sGroup, config) {
16884 this.init(id, sGroup, config);
16888 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16891 * When set to true, the utility automatically tries to scroll the browser
16892 * window wehn a drag and drop element is dragged near the viewport boundary.
16893 * Defaults to true.
16900 * Sets the pointer offset to the distance between the linked element's top
16901 * left corner and the location the element was clicked
16902 * @method autoOffset
16903 * @param {int} iPageX the X coordinate of the click
16904 * @param {int} iPageY the Y coordinate of the click
16906 autoOffset: function(iPageX, iPageY) {
16907 var x = iPageX - this.startPageX;
16908 var y = iPageY - this.startPageY;
16909 this.setDelta(x, y);
16913 * Sets the pointer offset. You can call this directly to force the
16914 * offset to be in a particular location (e.g., pass in 0,0 to set it
16915 * to the center of the object)
16917 * @param {int} iDeltaX the distance from the left
16918 * @param {int} iDeltaY the distance from the top
16920 setDelta: function(iDeltaX, iDeltaY) {
16921 this.deltaX = iDeltaX;
16922 this.deltaY = iDeltaY;
16926 * Sets the drag element to the location of the mousedown or click event,
16927 * maintaining the cursor location relative to the location on the element
16928 * that was clicked. Override this if you want to place the element in a
16929 * location other than where the cursor is.
16930 * @method setDragElPos
16931 * @param {int} iPageX the X coordinate of the mousedown or drag event
16932 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16934 setDragElPos: function(iPageX, iPageY) {
16935 // the first time we do this, we are going to check to make sure
16936 // the element has css positioning
16938 var el = this.getDragEl();
16939 this.alignElWithMouse(el, iPageX, iPageY);
16943 * Sets the element to the location of the mousedown or click event,
16944 * maintaining the cursor location relative to the location on the element
16945 * that was clicked. Override this if you want to place the element in a
16946 * location other than where the cursor is.
16947 * @method alignElWithMouse
16948 * @param {HTMLElement} el the element to move
16949 * @param {int} iPageX the X coordinate of the mousedown or drag event
16950 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16952 alignElWithMouse: function(el, iPageX, iPageY) {
16953 var oCoord = this.getTargetCoord(iPageX, iPageY);
16954 var fly = el.dom ? el : Roo.fly(el);
16955 if (!this.deltaSetXY) {
16956 var aCoord = [oCoord.x, oCoord.y];
16958 var newLeft = fly.getLeft(true);
16959 var newTop = fly.getTop(true);
16960 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16962 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16965 this.cachePosition(oCoord.x, oCoord.y);
16966 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16971 * Saves the most recent position so that we can reset the constraints and
16972 * tick marks on-demand. We need to know this so that we can calculate the
16973 * number of pixels the element is offset from its original position.
16974 * @method cachePosition
16975 * @param iPageX the current x position (optional, this just makes it so we
16976 * don't have to look it up again)
16977 * @param iPageY the current y position (optional, this just makes it so we
16978 * don't have to look it up again)
16980 cachePosition: function(iPageX, iPageY) {
16982 this.lastPageX = iPageX;
16983 this.lastPageY = iPageY;
16985 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16986 this.lastPageX = aCoord[0];
16987 this.lastPageY = aCoord[1];
16992 * Auto-scroll the window if the dragged object has been moved beyond the
16993 * visible window boundary.
16994 * @method autoScroll
16995 * @param {int} x the drag element's x position
16996 * @param {int} y the drag element's y position
16997 * @param {int} h the height of the drag element
16998 * @param {int} w the width of the drag element
17001 autoScroll: function(x, y, h, w) {
17004 // The client height
17005 var clientH = Roo.lib.Dom.getViewWidth();
17007 // The client width
17008 var clientW = Roo.lib.Dom.getViewHeight();
17010 // The amt scrolled down
17011 var st = this.DDM.getScrollTop();
17013 // The amt scrolled right
17014 var sl = this.DDM.getScrollLeft();
17016 // Location of the bottom of the element
17019 // Location of the right of the element
17022 // The distance from the cursor to the bottom of the visible area,
17023 // adjusted so that we don't scroll if the cursor is beyond the
17024 // element drag constraints
17025 var toBot = (clientH + st - y - this.deltaY);
17027 // The distance from the cursor to the right of the visible area
17028 var toRight = (clientW + sl - x - this.deltaX);
17031 // How close to the edge the cursor must be before we scroll
17032 // var thresh = (document.all) ? 100 : 40;
17035 // How many pixels to scroll per autoscroll op. This helps to reduce
17036 // clunky scrolling. IE is more sensitive about this ... it needs this
17037 // value to be higher.
17038 var scrAmt = (document.all) ? 80 : 30;
17040 // Scroll down if we are near the bottom of the visible page and the
17041 // obj extends below the crease
17042 if ( bot > clientH && toBot < thresh ) {
17043 window.scrollTo(sl, st + scrAmt);
17046 // Scroll up if the window is scrolled down and the top of the object
17047 // goes above the top border
17048 if ( y < st && st > 0 && y - st < thresh ) {
17049 window.scrollTo(sl, st - scrAmt);
17052 // Scroll right if the obj is beyond the right border and the cursor is
17053 // near the border.
17054 if ( right > clientW && toRight < thresh ) {
17055 window.scrollTo(sl + scrAmt, st);
17058 // Scroll left if the window has been scrolled to the right and the obj
17059 // extends past the left border
17060 if ( x < sl && sl > 0 && x - sl < thresh ) {
17061 window.scrollTo(sl - scrAmt, st);
17067 * Finds the location the element should be placed if we want to move
17068 * it to where the mouse location less the click offset would place us.
17069 * @method getTargetCoord
17070 * @param {int} iPageX the X coordinate of the click
17071 * @param {int} iPageY the Y coordinate of the click
17072 * @return an object that contains the coordinates (Object.x and Object.y)
17075 getTargetCoord: function(iPageX, iPageY) {
17078 var x = iPageX - this.deltaX;
17079 var y = iPageY - this.deltaY;
17081 if (this.constrainX) {
17082 if (x < this.minX) { x = this.minX; }
17083 if (x > this.maxX) { x = this.maxX; }
17086 if (this.constrainY) {
17087 if (y < this.minY) { y = this.minY; }
17088 if (y > this.maxY) { y = this.maxY; }
17091 x = this.getTick(x, this.xTicks);
17092 y = this.getTick(y, this.yTicks);
17099 * Sets up config options specific to this class. Overrides
17100 * Roo.dd.DragDrop, but all versions of this method through the
17101 * inheritance chain are called
17103 applyConfig: function() {
17104 Roo.dd.DD.superclass.applyConfig.call(this);
17105 this.scroll = (this.config.scroll !== false);
17109 * Event that fires prior to the onMouseDown event. Overrides
17112 b4MouseDown: function(e) {
17113 // this.resetConstraints();
17114 this.autoOffset(e.getPageX(),
17119 * Event that fires prior to the onDrag event. Overrides
17122 b4Drag: function(e) {
17123 this.setDragElPos(e.getPageX(),
17127 toString: function() {
17128 return ("DD " + this.id);
17131 //////////////////////////////////////////////////////////////////////////
17132 // Debugging ygDragDrop events that can be overridden
17133 //////////////////////////////////////////////////////////////////////////
17135 startDrag: function(x, y) {
17138 onDrag: function(e) {
17141 onDragEnter: function(e, id) {
17144 onDragOver: function(e, id) {
17147 onDragOut: function(e, id) {
17150 onDragDrop: function(e, id) {
17153 endDrag: function(e) {
17160 * Ext JS Library 1.1.1
17161 * Copyright(c) 2006-2007, Ext JS, LLC.
17163 * Originally Released Under LGPL - original licence link has changed is not relivant.
17166 * <script type="text/javascript">
17170 * @class Roo.dd.DDProxy
17171 * A DragDrop implementation that inserts an empty, bordered div into
17172 * the document that follows the cursor during drag operations. At the time of
17173 * the click, the frame div is resized to the dimensions of the linked html
17174 * element, and moved to the exact location of the linked element.
17176 * References to the "frame" element refer to the single proxy element that
17177 * was created to be dragged in place of all DDProxy elements on the
17180 * @extends Roo.dd.DD
17182 * @param {String} id the id of the linked html element
17183 * @param {String} sGroup the group of related DragDrop objects
17184 * @param {object} config an object containing configurable attributes
17185 * Valid properties for DDProxy in addition to those in DragDrop:
17186 * resizeFrame, centerFrame, dragElId
17188 Roo.dd.DDProxy = function(id, sGroup, config) {
17190 this.init(id, sGroup, config);
17196 * The default drag frame div id
17197 * @property Roo.dd.DDProxy.dragElId
17201 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17203 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17206 * By default we resize the drag frame to be the same size as the element
17207 * we want to drag (this is to get the frame effect). We can turn it off
17208 * if we want a different behavior.
17209 * @property resizeFrame
17215 * By default the frame is positioned exactly where the drag element is, so
17216 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17217 * you do not have constraints on the obj is to have the drag frame centered
17218 * around the cursor. Set centerFrame to true for this effect.
17219 * @property centerFrame
17222 centerFrame: false,
17225 * Creates the proxy element if it does not yet exist
17226 * @method createFrame
17228 createFrame: function() {
17230 var body = document.body;
17232 if (!body || !body.firstChild) {
17233 setTimeout( function() { self.createFrame(); }, 50 );
17237 var div = this.getDragEl();
17240 div = document.createElement("div");
17241 div.id = this.dragElId;
17244 s.position = "absolute";
17245 s.visibility = "hidden";
17247 s.border = "2px solid #aaa";
17250 // appendChild can blow up IE if invoked prior to the window load event
17251 // while rendering a table. It is possible there are other scenarios
17252 // that would cause this to happen as well.
17253 body.insertBefore(div, body.firstChild);
17258 * Initialization for the drag frame element. Must be called in the
17259 * constructor of all subclasses
17260 * @method initFrame
17262 initFrame: function() {
17263 this.createFrame();
17266 applyConfig: function() {
17267 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17269 this.resizeFrame = (this.config.resizeFrame !== false);
17270 this.centerFrame = (this.config.centerFrame);
17271 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17275 * Resizes the drag frame to the dimensions of the clicked object, positions
17276 * it over the object, and finally displays it
17277 * @method showFrame
17278 * @param {int} iPageX X click position
17279 * @param {int} iPageY Y click position
17282 showFrame: function(iPageX, iPageY) {
17283 var el = this.getEl();
17284 var dragEl = this.getDragEl();
17285 var s = dragEl.style;
17287 this._resizeProxy();
17289 if (this.centerFrame) {
17290 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17291 Math.round(parseInt(s.height, 10)/2) );
17294 this.setDragElPos(iPageX, iPageY);
17296 Roo.fly(dragEl).show();
17300 * The proxy is automatically resized to the dimensions of the linked
17301 * element when a drag is initiated, unless resizeFrame is set to false
17302 * @method _resizeProxy
17305 _resizeProxy: function() {
17306 if (this.resizeFrame) {
17307 var el = this.getEl();
17308 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17312 // overrides Roo.dd.DragDrop
17313 b4MouseDown: function(e) {
17314 var x = e.getPageX();
17315 var y = e.getPageY();
17316 this.autoOffset(x, y);
17317 this.setDragElPos(x, y);
17320 // overrides Roo.dd.DragDrop
17321 b4StartDrag: function(x, y) {
17322 // show the drag frame
17323 this.showFrame(x, y);
17326 // overrides Roo.dd.DragDrop
17327 b4EndDrag: function(e) {
17328 Roo.fly(this.getDragEl()).hide();
17331 // overrides Roo.dd.DragDrop
17332 // By default we try to move the element to the last location of the frame.
17333 // This is so that the default behavior mirrors that of Roo.dd.DD.
17334 endDrag: function(e) {
17336 var lel = this.getEl();
17337 var del = this.getDragEl();
17339 // Show the drag frame briefly so we can get its position
17340 del.style.visibility = "";
17343 // Hide the linked element before the move to get around a Safari
17345 lel.style.visibility = "hidden";
17346 Roo.dd.DDM.moveToEl(lel, del);
17347 del.style.visibility = "hidden";
17348 lel.style.visibility = "";
17353 beforeMove : function(){
17357 afterDrag : function(){
17361 toString: function() {
17362 return ("DDProxy " + this.id);
17368 * Ext JS Library 1.1.1
17369 * Copyright(c) 2006-2007, Ext JS, LLC.
17371 * Originally Released Under LGPL - original licence link has changed is not relivant.
17374 * <script type="text/javascript">
17378 * @class Roo.dd.DDTarget
17379 * A DragDrop implementation that does not move, but can be a drop
17380 * target. You would get the same result by simply omitting implementation
17381 * for the event callbacks, but this way we reduce the processing cost of the
17382 * event listener and the callbacks.
17383 * @extends Roo.dd.DragDrop
17385 * @param {String} id the id of the element that is a drop target
17386 * @param {String} sGroup the group of related DragDrop objects
17387 * @param {object} config an object containing configurable attributes
17388 * Valid properties for DDTarget in addition to those in
17392 Roo.dd.DDTarget = function(id, sGroup, config) {
17394 this.initTarget(id, sGroup, config);
17396 if (config.listeners || config.events) {
17397 Roo.dd.DragDrop.superclass.constructor.call(this, {
17398 listeners : config.listeners || {},
17399 events : config.events || {}
17404 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17405 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17406 toString: function() {
17407 return ("DDTarget " + this.id);
17412 * Ext JS Library 1.1.1
17413 * Copyright(c) 2006-2007, Ext JS, LLC.
17415 * Originally Released Under LGPL - original licence link has changed is not relivant.
17418 * <script type="text/javascript">
17423 * @class Roo.dd.ScrollManager
17424 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17425 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17428 Roo.dd.ScrollManager = function(){
17429 var ddm = Roo.dd.DragDropMgr;
17434 var onStop = function(e){
17439 var triggerRefresh = function(){
17440 if(ddm.dragCurrent){
17441 ddm.refreshCache(ddm.dragCurrent.groups);
17445 var doScroll = function(){
17446 if(ddm.dragCurrent){
17447 var dds = Roo.dd.ScrollManager;
17449 if(proc.el.scroll(proc.dir, dds.increment)){
17453 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17458 var clearProc = function(){
17460 clearInterval(proc.id);
17467 var startProc = function(el, dir){
17471 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17474 var onFire = function(e, isDrop){
17475 if(isDrop || !ddm.dragCurrent){ return; }
17476 var dds = Roo.dd.ScrollManager;
17477 if(!dragEl || dragEl != ddm.dragCurrent){
17478 dragEl = ddm.dragCurrent;
17479 // refresh regions on drag start
17480 dds.refreshCache();
17483 var xy = Roo.lib.Event.getXY(e);
17484 var pt = new Roo.lib.Point(xy[0], xy[1]);
17485 for(var id in els){
17486 var el = els[id], r = el._region;
17487 if(r && r.contains(pt) && el.isScrollable()){
17488 if(r.bottom - pt.y <= dds.thresh){
17490 startProc(el, "down");
17493 }else if(r.right - pt.x <= dds.thresh){
17495 startProc(el, "left");
17498 }else if(pt.y - r.top <= dds.thresh){
17500 startProc(el, "up");
17503 }else if(pt.x - r.left <= dds.thresh){
17505 startProc(el, "right");
17514 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17515 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17519 * Registers new overflow element(s) to auto scroll
17520 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17522 register : function(el){
17523 if(el instanceof Array){
17524 for(var i = 0, len = el.length; i < len; i++) {
17525 this.register(el[i]);
17534 * Unregisters overflow element(s) so they are no longer scrolled
17535 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17537 unregister : function(el){
17538 if(el instanceof Array){
17539 for(var i = 0, len = el.length; i < len; i++) {
17540 this.unregister(el[i]);
17549 * The number of pixels from the edge of a container the pointer needs to be to
17550 * trigger scrolling (defaults to 25)
17556 * The number of pixels to scroll in each scroll increment (defaults to 50)
17562 * The frequency of scrolls in milliseconds (defaults to 500)
17568 * True to animate the scroll (defaults to true)
17574 * The animation duration in seconds -
17575 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17581 * Manually trigger a cache refresh.
17583 refreshCache : function(){
17584 for(var id in els){
17585 if(typeof els[id] == 'object'){ // for people extending the object prototype
17586 els[id]._region = els[id].getRegion();
17593 * Ext JS Library 1.1.1
17594 * Copyright(c) 2006-2007, Ext JS, LLC.
17596 * Originally Released Under LGPL - original licence link has changed is not relivant.
17599 * <script type="text/javascript">
17604 * @class Roo.dd.Registry
17605 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17606 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17609 Roo.dd.Registry = function(){
17612 var autoIdSeed = 0;
17614 var getId = function(el, autogen){
17615 if(typeof el == "string"){
17619 if(!id && autogen !== false){
17620 id = "roodd-" + (++autoIdSeed);
17628 * Register a drag drop element
17629 * @param {String|HTMLElement} element The id or DOM node to register
17630 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17631 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17632 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17633 * populated in the data object (if applicable):
17635 Value Description<br />
17636 --------- ------------------------------------------<br />
17637 handles Array of DOM nodes that trigger dragging<br />
17638 for the element being registered<br />
17639 isHandle True if the element passed in triggers<br />
17640 dragging itself, else false
17643 register : function(el, data){
17645 if(typeof el == "string"){
17646 el = document.getElementById(el);
17649 elements[getId(el)] = data;
17650 if(data.isHandle !== false){
17651 handles[data.ddel.id] = data;
17654 var hs = data.handles;
17655 for(var i = 0, len = hs.length; i < len; i++){
17656 handles[getId(hs[i])] = data;
17662 * Unregister a drag drop element
17663 * @param {String|HTMLElement} element The id or DOM node to unregister
17665 unregister : function(el){
17666 var id = getId(el, false);
17667 var data = elements[id];
17669 delete elements[id];
17671 var hs = data.handles;
17672 for(var i = 0, len = hs.length; i < len; i++){
17673 delete handles[getId(hs[i], false)];
17680 * Returns the handle registered for a DOM Node by id
17681 * @param {String|HTMLElement} id The DOM node or id to look up
17682 * @return {Object} handle The custom handle data
17684 getHandle : function(id){
17685 if(typeof id != "string"){ // must be element?
17688 return handles[id];
17692 * Returns the handle that is registered for the DOM node that is the target of the event
17693 * @param {Event} e The event
17694 * @return {Object} handle The custom handle data
17696 getHandleFromEvent : function(e){
17697 var t = Roo.lib.Event.getTarget(e);
17698 return t ? handles[t.id] : null;
17702 * Returns a custom data object that is registered for a DOM node by id
17703 * @param {String|HTMLElement} id The DOM node or id to look up
17704 * @return {Object} data The custom data
17706 getTarget : function(id){
17707 if(typeof id != "string"){ // must be element?
17710 return elements[id];
17714 * Returns a custom data object that is registered for the DOM node that is the target of the event
17715 * @param {Event} e The event
17716 * @return {Object} data The custom data
17718 getTargetFromEvent : function(e){
17719 var t = Roo.lib.Event.getTarget(e);
17720 return t ? elements[t.id] || handles[t.id] : null;
17725 * Ext JS Library 1.1.1
17726 * Copyright(c) 2006-2007, Ext JS, LLC.
17728 * Originally Released Under LGPL - original licence link has changed is not relivant.
17731 * <script type="text/javascript">
17736 * @class Roo.dd.StatusProxy
17737 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17738 * default drag proxy used by all Roo.dd components.
17740 * @param {Object} config
17742 Roo.dd.StatusProxy = function(config){
17743 Roo.apply(this, config);
17744 this.id = this.id || Roo.id();
17745 this.el = new Roo.Layer({
17747 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17748 {tag: "div", cls: "x-dd-drop-icon"},
17749 {tag: "div", cls: "x-dd-drag-ghost"}
17752 shadow: !config || config.shadow !== false
17754 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17755 this.dropStatus = this.dropNotAllowed;
17758 Roo.dd.StatusProxy.prototype = {
17760 * @cfg {String} dropAllowed
17761 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17763 dropAllowed : "x-dd-drop-ok",
17765 * @cfg {String} dropNotAllowed
17766 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17768 dropNotAllowed : "x-dd-drop-nodrop",
17771 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17772 * over the current target element.
17773 * @param {String} cssClass The css class for the new drop status indicator image
17775 setStatus : function(cssClass){
17776 cssClass = cssClass || this.dropNotAllowed;
17777 if(this.dropStatus != cssClass){
17778 this.el.replaceClass(this.dropStatus, cssClass);
17779 this.dropStatus = cssClass;
17784 * Resets the status indicator to the default dropNotAllowed value
17785 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17787 reset : function(clearGhost){
17788 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17789 this.dropStatus = this.dropNotAllowed;
17791 this.ghost.update("");
17796 * Updates the contents of the ghost element
17797 * @param {String} html The html that will replace the current innerHTML of the ghost element
17799 update : function(html){
17800 if(typeof html == "string"){
17801 this.ghost.update(html);
17803 this.ghost.update("");
17804 html.style.margin = "0";
17805 this.ghost.dom.appendChild(html);
17807 // ensure float = none set?? cant remember why though.
17808 var el = this.ghost.dom.firstChild;
17810 Roo.fly(el).setStyle('float', 'none');
17815 * Returns the underlying proxy {@link Roo.Layer}
17816 * @return {Roo.Layer} el
17818 getEl : function(){
17823 * Returns the ghost element
17824 * @return {Roo.Element} el
17826 getGhost : function(){
17832 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17834 hide : function(clear){
17842 * Stops the repair animation if it's currently running
17845 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17851 * Displays this proxy
17858 * Force the Layer to sync its shadow and shim positions to the element
17865 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17866 * invalid drop operation by the item being dragged.
17867 * @param {Array} xy The XY position of the element ([x, y])
17868 * @param {Function} callback The function to call after the repair is complete
17869 * @param {Object} scope The scope in which to execute the callback
17871 repair : function(xy, callback, scope){
17872 this.callback = callback;
17873 this.scope = scope;
17874 if(xy && this.animRepair !== false){
17875 this.el.addClass("x-dd-drag-repair");
17876 this.el.hideUnders(true);
17877 this.anim = this.el.shift({
17878 duration: this.repairDuration || .5,
17882 callback: this.afterRepair,
17886 this.afterRepair();
17891 afterRepair : function(){
17893 if(typeof this.callback == "function"){
17894 this.callback.call(this.scope || this);
17896 this.callback = null;
17901 * Ext JS Library 1.1.1
17902 * Copyright(c) 2006-2007, Ext JS, LLC.
17904 * Originally Released Under LGPL - original licence link has changed is not relivant.
17907 * <script type="text/javascript">
17911 * @class Roo.dd.DragSource
17912 * @extends Roo.dd.DDProxy
17913 * A simple class that provides the basic implementation needed to make any element draggable.
17915 * @param {String/HTMLElement/Element} el The container element
17916 * @param {Object} config
17918 Roo.dd.DragSource = function(el, config){
17919 this.el = Roo.get(el);
17920 this.dragData = {};
17922 Roo.apply(this, config);
17925 this.proxy = new Roo.dd.StatusProxy();
17928 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17929 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17931 this.dragging = false;
17934 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17936 * @cfg {String} dropAllowed
17937 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17939 dropAllowed : "x-dd-drop-ok",
17941 * @cfg {String} dropNotAllowed
17942 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17944 dropNotAllowed : "x-dd-drop-nodrop",
17947 * Returns the data object associated with this drag source
17948 * @return {Object} data An object containing arbitrary data
17950 getDragData : function(e){
17951 return this.dragData;
17955 onDragEnter : function(e, id){
17956 var target = Roo.dd.DragDropMgr.getDDById(id);
17957 this.cachedTarget = target;
17958 if(this.beforeDragEnter(target, e, id) !== false){
17959 if(target.isNotifyTarget){
17960 var status = target.notifyEnter(this, e, this.dragData);
17961 this.proxy.setStatus(status);
17963 this.proxy.setStatus(this.dropAllowed);
17966 if(this.afterDragEnter){
17968 * An empty function by default, but provided so that you can perform a custom action
17969 * when the dragged item enters the drop target by providing an implementation.
17970 * @param {Roo.dd.DragDrop} target The drop target
17971 * @param {Event} e The event object
17972 * @param {String} id The id of the dragged element
17973 * @method afterDragEnter
17975 this.afterDragEnter(target, e, id);
17981 * An empty function by default, but provided so that you can perform a custom action
17982 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17983 * @param {Roo.dd.DragDrop} target The drop target
17984 * @param {Event} e The event object
17985 * @param {String} id The id of the dragged element
17986 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17988 beforeDragEnter : function(target, e, id){
17993 alignElWithMouse: function() {
17994 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17999 onDragOver : function(e, id){
18000 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18001 if(this.beforeDragOver(target, e, id) !== false){
18002 if(target.isNotifyTarget){
18003 var status = target.notifyOver(this, e, this.dragData);
18004 this.proxy.setStatus(status);
18007 if(this.afterDragOver){
18009 * An empty function by default, but provided so that you can perform a custom action
18010 * while the dragged item is over the drop target by providing an implementation.
18011 * @param {Roo.dd.DragDrop} target The drop target
18012 * @param {Event} e The event object
18013 * @param {String} id The id of the dragged element
18014 * @method afterDragOver
18016 this.afterDragOver(target, e, id);
18022 * An empty function by default, but provided so that you can perform a custom action
18023 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18024 * @param {Roo.dd.DragDrop} target The drop target
18025 * @param {Event} e The event object
18026 * @param {String} id The id of the dragged element
18027 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18029 beforeDragOver : function(target, e, id){
18034 onDragOut : function(e, id){
18035 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18036 if(this.beforeDragOut(target, e, id) !== false){
18037 if(target.isNotifyTarget){
18038 target.notifyOut(this, e, this.dragData);
18040 this.proxy.reset();
18041 if(this.afterDragOut){
18043 * An empty function by default, but provided so that you can perform a custom action
18044 * after the dragged item is dragged out of the target without dropping.
18045 * @param {Roo.dd.DragDrop} target The drop target
18046 * @param {Event} e The event object
18047 * @param {String} id The id of the dragged element
18048 * @method afterDragOut
18050 this.afterDragOut(target, e, id);
18053 this.cachedTarget = null;
18057 * An empty function by default, but provided so that you can perform a custom action before the dragged
18058 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18059 * @param {Roo.dd.DragDrop} target The drop target
18060 * @param {Event} e The event object
18061 * @param {String} id The id of the dragged element
18062 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18064 beforeDragOut : function(target, e, id){
18069 onDragDrop : function(e, id){
18070 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18071 if(this.beforeDragDrop(target, e, id) !== false){
18072 if(target.isNotifyTarget){
18073 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18074 this.onValidDrop(target, e, id);
18076 this.onInvalidDrop(target, e, id);
18079 this.onValidDrop(target, e, id);
18082 if(this.afterDragDrop){
18084 * An empty function by default, but provided so that you can perform a custom action
18085 * after a valid drag drop has occurred by providing an implementation.
18086 * @param {Roo.dd.DragDrop} target The drop target
18087 * @param {Event} e The event object
18088 * @param {String} id The id of the dropped element
18089 * @method afterDragDrop
18091 this.afterDragDrop(target, e, id);
18094 delete this.cachedTarget;
18098 * An empty function by default, but provided so that you can perform a custom action before the dragged
18099 * item is dropped onto the target and optionally cancel the onDragDrop.
18100 * @param {Roo.dd.DragDrop} target The drop target
18101 * @param {Event} e The event object
18102 * @param {String} id The id of the dragged element
18103 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18105 beforeDragDrop : function(target, e, id){
18110 onValidDrop : function(target, e, id){
18112 if(this.afterValidDrop){
18114 * An empty function by default, but provided so that you can perform a custom action
18115 * after a valid drop has occurred by providing an implementation.
18116 * @param {Object} target The target DD
18117 * @param {Event} e The event object
18118 * @param {String} id The id of the dropped element
18119 * @method afterInvalidDrop
18121 this.afterValidDrop(target, e, id);
18126 getRepairXY : function(e, data){
18127 return this.el.getXY();
18131 onInvalidDrop : function(target, e, id){
18132 this.beforeInvalidDrop(target, e, id);
18133 if(this.cachedTarget){
18134 if(this.cachedTarget.isNotifyTarget){
18135 this.cachedTarget.notifyOut(this, e, this.dragData);
18137 this.cacheTarget = null;
18139 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18141 if(this.afterInvalidDrop){
18143 * An empty function by default, but provided so that you can perform a custom action
18144 * after an invalid drop has occurred by providing an implementation.
18145 * @param {Event} e The event object
18146 * @param {String} id The id of the dropped element
18147 * @method afterInvalidDrop
18149 this.afterInvalidDrop(e, id);
18154 afterRepair : function(){
18156 this.el.highlight(this.hlColor || "c3daf9");
18158 this.dragging = false;
18162 * An empty function by default, but provided so that you can perform a custom action after an invalid
18163 * drop has occurred.
18164 * @param {Roo.dd.DragDrop} target The drop target
18165 * @param {Event} e The event object
18166 * @param {String} id The id of the dragged element
18167 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18169 beforeInvalidDrop : function(target, e, id){
18174 handleMouseDown : function(e){
18175 if(this.dragging) {
18178 var data = this.getDragData(e);
18179 if(data && this.onBeforeDrag(data, e) !== false){
18180 this.dragData = data;
18182 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18187 * An empty function by default, but provided so that you can perform a custom action before the initial
18188 * drag event begins and optionally cancel it.
18189 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18190 * @param {Event} e The event object
18191 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18193 onBeforeDrag : function(data, e){
18198 * An empty function by default, but provided so that you can perform a custom action once the initial
18199 * drag event has begun. The drag cannot be canceled from this function.
18200 * @param {Number} x The x position of the click on the dragged object
18201 * @param {Number} y The y position of the click on the dragged object
18203 onStartDrag : Roo.emptyFn,
18205 // private - YUI override
18206 startDrag : function(x, y){
18207 this.proxy.reset();
18208 this.dragging = true;
18209 this.proxy.update("");
18210 this.onInitDrag(x, y);
18215 onInitDrag : function(x, y){
18216 var clone = this.el.dom.cloneNode(true);
18217 clone.id = Roo.id(); // prevent duplicate ids
18218 this.proxy.update(clone);
18219 this.onStartDrag(x, y);
18224 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18225 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18227 getProxy : function(){
18232 * Hides the drag source's {@link Roo.dd.StatusProxy}
18234 hideProxy : function(){
18236 this.proxy.reset(true);
18237 this.dragging = false;
18241 triggerCacheRefresh : function(){
18242 Roo.dd.DDM.refreshCache(this.groups);
18245 // private - override to prevent hiding
18246 b4EndDrag: function(e) {
18249 // private - override to prevent moving
18250 endDrag : function(e){
18251 this.onEndDrag(this.dragData, e);
18255 onEndDrag : function(data, e){
18258 // private - pin to cursor
18259 autoOffset : function(x, y) {
18260 this.setDelta(-12, -20);
18264 * Ext JS Library 1.1.1
18265 * Copyright(c) 2006-2007, Ext JS, LLC.
18267 * Originally Released Under LGPL - original licence link has changed is not relivant.
18270 * <script type="text/javascript">
18275 * @class Roo.dd.DropTarget
18276 * @extends Roo.dd.DDTarget
18277 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18278 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18280 * @param {String/HTMLElement/Element} el The container element
18281 * @param {Object} config
18283 Roo.dd.DropTarget = function(el, config){
18284 this.el = Roo.get(el);
18286 var listeners = false; ;
18287 if (config && config.listeners) {
18288 listeners= config.listeners;
18289 delete config.listeners;
18291 Roo.apply(this, config);
18293 if(this.containerScroll){
18294 Roo.dd.ScrollManager.register(this.el);
18298 * @scope Roo.dd.DropTarget
18303 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18304 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18305 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18307 * IMPORTANT : it should set this.overClass and this.dropAllowed
18309 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18310 * @param {Event} e The event
18311 * @param {Object} data An object containing arbitrary data supplied by the drag source
18317 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18318 * This method will be called on every mouse movement while the drag source is over the drop target.
18319 * This default implementation simply returns the dropAllowed config value.
18321 * IMPORTANT : it should set this.dropAllowed
18323 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18324 * @param {Event} e The event
18325 * @param {Object} data An object containing arbitrary data supplied by the drag source
18331 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18332 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18333 * overClass (if any) from the drop element.
18334 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18335 * @param {Event} e The event
18336 * @param {Object} data An object containing arbitrary data supplied by the drag source
18342 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18343 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18344 * implementation that does something to process the drop event and returns true so that the drag source's
18345 * repair action does not run.
18347 * IMPORTANT : it should set this.success
18349 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18350 * @param {Event} e The event
18351 * @param {Object} data An object containing arbitrary data supplied by the drag source
18357 Roo.dd.DropTarget.superclass.constructor.call( this,
18359 this.ddGroup || this.group,
18362 listeners : listeners || {}
18370 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18372 * @cfg {String} overClass
18373 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18376 * @cfg {String} ddGroup
18377 * The drag drop group to handle drop events for
18381 * @cfg {String} dropAllowed
18382 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18384 dropAllowed : "x-dd-drop-ok",
18386 * @cfg {String} dropNotAllowed
18387 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18389 dropNotAllowed : "x-dd-drop-nodrop",
18391 * @cfg {boolean} success
18392 * set this after drop listener..
18396 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18397 * if the drop point is valid for over/enter..
18404 isNotifyTarget : true,
18409 notifyEnter : function(dd, e, data)
18412 this.fireEvent('enter', dd, e, data);
18413 if(this.overClass){
18414 this.el.addClass(this.overClass);
18416 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18417 this.valid ? this.dropAllowed : this.dropNotAllowed
18424 notifyOver : function(dd, e, data)
18427 this.fireEvent('over', dd, e, data);
18428 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18429 this.valid ? this.dropAllowed : this.dropNotAllowed
18436 notifyOut : function(dd, e, data)
18438 this.fireEvent('out', dd, e, data);
18439 if(this.overClass){
18440 this.el.removeClass(this.overClass);
18447 notifyDrop : function(dd, e, data)
18449 this.success = false;
18450 this.fireEvent('drop', dd, e, data);
18451 return this.success;
18455 * Ext JS Library 1.1.1
18456 * Copyright(c) 2006-2007, Ext JS, LLC.
18458 * Originally Released Under LGPL - original licence link has changed is not relivant.
18461 * <script type="text/javascript">
18466 * @class Roo.dd.DragZone
18467 * @extends Roo.dd.DragSource
18468 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18469 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18471 * @param {String/HTMLElement/Element} el The container element
18472 * @param {Object} config
18474 Roo.dd.DragZone = function(el, config){
18475 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18476 if(this.containerScroll){
18477 Roo.dd.ScrollManager.register(this.el);
18481 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18483 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18484 * for auto scrolling during drag operations.
18487 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18488 * method after a failed drop (defaults to "c3daf9" - light blue)
18492 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18493 * for a valid target to drag based on the mouse down. Override this method
18494 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18495 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18496 * @param {EventObject} e The mouse down event
18497 * @return {Object} The dragData
18499 getDragData : function(e){
18500 return Roo.dd.Registry.getHandleFromEvent(e);
18504 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18505 * this.dragData.ddel
18506 * @param {Number} x The x position of the click on the dragged object
18507 * @param {Number} y The y position of the click on the dragged object
18508 * @return {Boolean} true to continue the drag, false to cancel
18510 onInitDrag : function(x, y){
18511 this.proxy.update(this.dragData.ddel.cloneNode(true));
18512 this.onStartDrag(x, y);
18517 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18519 afterRepair : function(){
18521 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18523 this.dragging = false;
18527 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18528 * the XY of this.dragData.ddel
18529 * @param {EventObject} e The mouse up event
18530 * @return {Array} The xy location (e.g. [100, 200])
18532 getRepairXY : function(e){
18533 return Roo.Element.fly(this.dragData.ddel).getXY();
18537 * Ext JS Library 1.1.1
18538 * Copyright(c) 2006-2007, Ext JS, LLC.
18540 * Originally Released Under LGPL - original licence link has changed is not relivant.
18543 * <script type="text/javascript">
18546 * @class Roo.dd.DropZone
18547 * @extends Roo.dd.DropTarget
18548 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18549 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18551 * @param {String/HTMLElement/Element} el The container element
18552 * @param {Object} config
18554 Roo.dd.DropZone = function(el, config){
18555 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18558 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18560 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18561 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18562 * provide your own custom lookup.
18563 * @param {Event} e The event
18564 * @return {Object} data The custom data
18566 getTargetFromEvent : function(e){
18567 return Roo.dd.Registry.getTargetFromEvent(e);
18571 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18572 * that it has registered. This method has no default implementation and should be overridden to provide
18573 * node-specific processing if necessary.
18574 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18575 * {@link #getTargetFromEvent} for this node)
18576 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18577 * @param {Event} e The event
18578 * @param {Object} data An object containing arbitrary data supplied by the drag source
18580 onNodeEnter : function(n, dd, e, data){
18585 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18586 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18587 * overridden to provide the proper feedback.
18588 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18589 * {@link #getTargetFromEvent} for this node)
18590 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18591 * @param {Event} e The event
18592 * @param {Object} data An object containing arbitrary data supplied by the drag source
18593 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18594 * underlying {@link Roo.dd.StatusProxy} can be updated
18596 onNodeOver : function(n, dd, e, data){
18597 return this.dropAllowed;
18601 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18602 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18603 * node-specific processing if necessary.
18604 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18605 * {@link #getTargetFromEvent} for this node)
18606 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18607 * @param {Event} e The event
18608 * @param {Object} data An object containing arbitrary data supplied by the drag source
18610 onNodeOut : function(n, dd, e, data){
18615 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18616 * the drop node. The default implementation returns false, so it should be overridden to provide the
18617 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18618 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18619 * {@link #getTargetFromEvent} for this node)
18620 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18621 * @param {Event} e The event
18622 * @param {Object} data An object containing arbitrary data supplied by the drag source
18623 * @return {Boolean} True if the drop was valid, else false
18625 onNodeDrop : function(n, dd, e, data){
18630 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18631 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18632 * it should be overridden to provide the proper feedback if necessary.
18633 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18634 * @param {Event} e The event
18635 * @param {Object} data An object containing arbitrary data supplied by the drag source
18636 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18637 * underlying {@link Roo.dd.StatusProxy} can be updated
18639 onContainerOver : function(dd, e, data){
18640 return this.dropNotAllowed;
18644 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18645 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18646 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18647 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18648 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18649 * @param {Event} e The event
18650 * @param {Object} data An object containing arbitrary data supplied by the drag source
18651 * @return {Boolean} True if the drop was valid, else false
18653 onContainerDrop : function(dd, e, data){
18658 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18659 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18660 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18661 * you should override this method and provide a custom implementation.
18662 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18663 * @param {Event} e The event
18664 * @param {Object} data An object containing arbitrary data supplied by the drag source
18665 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18666 * underlying {@link Roo.dd.StatusProxy} can be updated
18668 notifyEnter : function(dd, e, data){
18669 return this.dropNotAllowed;
18673 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18674 * This method will be called on every mouse movement while the drag source is over the drop zone.
18675 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18676 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18677 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18678 * registered node, it will call {@link #onContainerOver}.
18679 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18680 * @param {Event} e The event
18681 * @param {Object} data An object containing arbitrary data supplied by the drag source
18682 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18683 * underlying {@link Roo.dd.StatusProxy} can be updated
18685 notifyOver : function(dd, e, data){
18686 var n = this.getTargetFromEvent(e);
18687 if(!n){ // not over valid drop target
18688 if(this.lastOverNode){
18689 this.onNodeOut(this.lastOverNode, dd, e, data);
18690 this.lastOverNode = null;
18692 return this.onContainerOver(dd, e, data);
18694 if(this.lastOverNode != n){
18695 if(this.lastOverNode){
18696 this.onNodeOut(this.lastOverNode, dd, e, data);
18698 this.onNodeEnter(n, dd, e, data);
18699 this.lastOverNode = n;
18701 return this.onNodeOver(n, dd, e, data);
18705 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18706 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18707 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18708 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18709 * @param {Event} e The event
18710 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18712 notifyOut : function(dd, e, data){
18713 if(this.lastOverNode){
18714 this.onNodeOut(this.lastOverNode, dd, e, data);
18715 this.lastOverNode = null;
18720 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18721 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18722 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18723 * otherwise it will call {@link #onContainerDrop}.
18724 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18725 * @param {Event} e The event
18726 * @param {Object} data An object containing arbitrary data supplied by the drag source
18727 * @return {Boolean} True if the drop was valid, else false
18729 notifyDrop : function(dd, e, data){
18730 if(this.lastOverNode){
18731 this.onNodeOut(this.lastOverNode, dd, e, data);
18732 this.lastOverNode = null;
18734 var n = this.getTargetFromEvent(e);
18736 this.onNodeDrop(n, dd, e, data) :
18737 this.onContainerDrop(dd, e, data);
18741 triggerCacheRefresh : function(){
18742 Roo.dd.DDM.refreshCache(this.groups);
18746 * Ext JS Library 1.1.1
18747 * Copyright(c) 2006-2007, Ext JS, LLC.
18749 * Originally Released Under LGPL - original licence link has changed is not relivant.
18752 * <script type="text/javascript">
18757 * @class Roo.data.SortTypes
18759 * Defines the default sorting (casting?) comparison functions used when sorting data.
18761 Roo.data.SortTypes = {
18763 * Default sort that does nothing
18764 * @param {Mixed} s The value being converted
18765 * @return {Mixed} The comparison value
18767 none : function(s){
18772 * The regular expression used to strip tags
18776 stripTagsRE : /<\/?[^>]+>/gi,
18779 * Strips all HTML tags to sort on text only
18780 * @param {Mixed} s The value being converted
18781 * @return {String} The comparison value
18783 asText : function(s){
18784 return String(s).replace(this.stripTagsRE, "");
18788 * Strips all HTML tags to sort on text only - Case insensitive
18789 * @param {Mixed} s The value being converted
18790 * @return {String} The comparison value
18792 asUCText : function(s){
18793 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18797 * Case insensitive string
18798 * @param {Mixed} s The value being converted
18799 * @return {String} The comparison value
18801 asUCString : function(s) {
18802 return String(s).toUpperCase();
18807 * @param {Mixed} s The value being converted
18808 * @return {Number} The comparison value
18810 asDate : function(s) {
18814 if(s instanceof Date){
18815 return s.getTime();
18817 return Date.parse(String(s));
18822 * @param {Mixed} s The value being converted
18823 * @return {Float} The comparison value
18825 asFloat : function(s) {
18826 var val = parseFloat(String(s).replace(/,/g, ""));
18827 if(isNaN(val)) val = 0;
18833 * @param {Mixed} s The value being converted
18834 * @return {Number} The comparison value
18836 asInt : function(s) {
18837 var val = parseInt(String(s).replace(/,/g, ""));
18838 if(isNaN(val)) val = 0;
18843 * Ext JS Library 1.1.1
18844 * Copyright(c) 2006-2007, Ext JS, LLC.
18846 * Originally Released Under LGPL - original licence link has changed is not relivant.
18849 * <script type="text/javascript">
18853 * @class Roo.data.Record
18854 * Instances of this class encapsulate both record <em>definition</em> information, and record
18855 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18856 * to access Records cached in an {@link Roo.data.Store} object.<br>
18858 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18859 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18862 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18864 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18865 * {@link #create}. The parameters are the same.
18866 * @param {Array} data An associative Array of data values keyed by the field name.
18867 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18868 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18869 * not specified an integer id is generated.
18871 Roo.data.Record = function(data, id){
18872 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18877 * Generate a constructor for a specific record layout.
18878 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18879 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18880 * Each field definition object may contain the following properties: <ul>
18881 * <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,
18882 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18883 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18884 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18885 * is being used, then this is a string containing the javascript expression to reference the data relative to
18886 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18887 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18888 * this may be omitted.</p></li>
18889 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18890 * <ul><li>auto (Default, implies no conversion)</li>
18895 * <li>date</li></ul></p></li>
18896 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18897 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18898 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18899 * by the Reader into an object that will be stored in the Record. It is passed the
18900 * following parameters:<ul>
18901 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18903 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18905 * <br>usage:<br><pre><code>
18906 var TopicRecord = Roo.data.Record.create(
18907 {name: 'title', mapping: 'topic_title'},
18908 {name: 'author', mapping: 'username'},
18909 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18910 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18911 {name: 'lastPoster', mapping: 'user2'},
18912 {name: 'excerpt', mapping: 'post_text'}
18915 var myNewRecord = new TopicRecord({
18916 title: 'Do my job please',
18919 lastPost: new Date(),
18920 lastPoster: 'Animal',
18921 excerpt: 'No way dude!'
18923 myStore.add(myNewRecord);
18928 Roo.data.Record.create = function(o){
18929 var f = function(){
18930 f.superclass.constructor.apply(this, arguments);
18932 Roo.extend(f, Roo.data.Record);
18933 var p = f.prototype;
18934 p.fields = new Roo.util.MixedCollection(false, function(field){
18937 for(var i = 0, len = o.length; i < len; i++){
18938 p.fields.add(new Roo.data.Field(o[i]));
18940 f.getField = function(name){
18941 return p.fields.get(name);
18946 Roo.data.Record.AUTO_ID = 1000;
18947 Roo.data.Record.EDIT = 'edit';
18948 Roo.data.Record.REJECT = 'reject';
18949 Roo.data.Record.COMMIT = 'commit';
18951 Roo.data.Record.prototype = {
18953 * Readonly flag - true if this record has been modified.
18962 join : function(store){
18963 this.store = store;
18967 * Set the named field to the specified value.
18968 * @param {String} name The name of the field to set.
18969 * @param {Object} value The value to set the field to.
18971 set : function(name, value){
18972 if(this.data[name] == value){
18976 if(!this.modified){
18977 this.modified = {};
18979 if(typeof this.modified[name] == 'undefined'){
18980 this.modified[name] = this.data[name];
18982 this.data[name] = value;
18984 this.store.afterEdit(this);
18989 * Get the value of the named field.
18990 * @param {String} name The name of the field to get the value of.
18991 * @return {Object} The value of the field.
18993 get : function(name){
18994 return this.data[name];
18998 beginEdit : function(){
18999 this.editing = true;
19000 this.modified = {};
19004 cancelEdit : function(){
19005 this.editing = false;
19006 delete this.modified;
19010 endEdit : function(){
19011 this.editing = false;
19012 if(this.dirty && this.store){
19013 this.store.afterEdit(this);
19018 * Usually called by the {@link Roo.data.Store} which owns the Record.
19019 * Rejects all changes made to the Record since either creation, or the last commit operation.
19020 * Modified fields are reverted to their original values.
19022 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19023 * of reject operations.
19025 reject : function(){
19026 var m = this.modified;
19028 if(typeof m[n] != "function"){
19029 this.data[n] = m[n];
19032 this.dirty = false;
19033 delete this.modified;
19034 this.editing = false;
19036 this.store.afterReject(this);
19041 * Usually called by the {@link Roo.data.Store} which owns the Record.
19042 * Commits all changes made to the Record since either creation, or the last commit operation.
19044 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19045 * of commit operations.
19047 commit : function(){
19048 this.dirty = false;
19049 delete this.modified;
19050 this.editing = false;
19052 this.store.afterCommit(this);
19057 hasError : function(){
19058 return this.error != null;
19062 clearError : function(){
19067 * Creates a copy of this record.
19068 * @param {String} id (optional) A new record id if you don't want to use this record's id
19071 copy : function(newId) {
19072 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19076 * Ext JS Library 1.1.1
19077 * Copyright(c) 2006-2007, Ext JS, LLC.
19079 * Originally Released Under LGPL - original licence link has changed is not relivant.
19082 * <script type="text/javascript">
19088 * @class Roo.data.Store
19089 * @extends Roo.util.Observable
19090 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19091 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19093 * 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
19094 * has no knowledge of the format of the data returned by the Proxy.<br>
19096 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19097 * instances from the data object. These records are cached and made available through accessor functions.
19099 * Creates a new Store.
19100 * @param {Object} config A config object containing the objects needed for the Store to access data,
19101 * and read the data into Records.
19103 Roo.data.Store = function(config){
19104 this.data = new Roo.util.MixedCollection(false);
19105 this.data.getKey = function(o){
19108 this.baseParams = {};
19110 this.paramNames = {
19117 if(config && config.data){
19118 this.inlineData = config.data;
19119 delete config.data;
19122 Roo.apply(this, config);
19124 if(this.reader){ // reader passed
19125 this.reader = Roo.factory(this.reader, Roo.data);
19126 this.reader.xmodule = this.xmodule || false;
19127 if(!this.recordType){
19128 this.recordType = this.reader.recordType;
19130 if(this.reader.onMetaChange){
19131 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19135 if(this.recordType){
19136 this.fields = this.recordType.prototype.fields;
19138 this.modified = [];
19142 * @event datachanged
19143 * Fires when the data cache has changed, and a widget which is using this Store
19144 * as a Record cache should refresh its view.
19145 * @param {Store} this
19147 datachanged : true,
19149 * @event metachange
19150 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19151 * @param {Store} this
19152 * @param {Object} meta The JSON metadata
19157 * Fires when Records have been added to the Store
19158 * @param {Store} this
19159 * @param {Roo.data.Record[]} records The array of Records added
19160 * @param {Number} index The index at which the record(s) were added
19165 * Fires when a Record has been removed from the Store
19166 * @param {Store} this
19167 * @param {Roo.data.Record} record The Record that was removed
19168 * @param {Number} index The index at which the record was removed
19173 * Fires when a Record has been updated
19174 * @param {Store} this
19175 * @param {Roo.data.Record} record The Record that was updated
19176 * @param {String} operation The update operation being performed. Value may be one of:
19178 Roo.data.Record.EDIT
19179 Roo.data.Record.REJECT
19180 Roo.data.Record.COMMIT
19186 * Fires when the data cache has been cleared.
19187 * @param {Store} this
19191 * @event beforeload
19192 * Fires before a request is made for a new data object. If the beforeload handler returns false
19193 * the load action will be canceled.
19194 * @param {Store} this
19195 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19200 * Fires after a new set of Records has been loaded.
19201 * @param {Store} this
19202 * @param {Roo.data.Record[]} records The Records that were loaded
19203 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19207 * @event loadexception
19208 * Fires if an exception occurs in the Proxy during loading.
19209 * Called with the signature of the Proxy's "loadexception" event.
19210 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19213 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19214 * @param {Object} load options
19215 * @param {Object} jsonData from your request (normally this contains the Exception)
19217 loadexception : true
19221 this.proxy = Roo.factory(this.proxy, Roo.data);
19222 this.proxy.xmodule = this.xmodule || false;
19223 this.relayEvents(this.proxy, ["loadexception"]);
19225 this.sortToggle = {};
19227 Roo.data.Store.superclass.constructor.call(this);
19229 if(this.inlineData){
19230 this.loadData(this.inlineData);
19231 delete this.inlineData;
19234 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19236 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19237 * without a remote query - used by combo/forms at present.
19241 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19244 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19247 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19248 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19251 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19252 * on any HTTP request
19255 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19258 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19259 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19261 remoteSort : false,
19264 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19265 * loaded or when a record is removed. (defaults to false).
19267 pruneModifiedRecords : false,
19270 lastOptions : null,
19273 * Add Records to the Store and fires the add event.
19274 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19276 add : function(records){
19277 records = [].concat(records);
19278 for(var i = 0, len = records.length; i < len; i++){
19279 records[i].join(this);
19281 var index = this.data.length;
19282 this.data.addAll(records);
19283 this.fireEvent("add", this, records, index);
19287 * Remove a Record from the Store and fires the remove event.
19288 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19290 remove : function(record){
19291 var index = this.data.indexOf(record);
19292 this.data.removeAt(index);
19293 if(this.pruneModifiedRecords){
19294 this.modified.remove(record);
19296 this.fireEvent("remove", this, record, index);
19300 * Remove all Records from the Store and fires the clear event.
19302 removeAll : function(){
19304 if(this.pruneModifiedRecords){
19305 this.modified = [];
19307 this.fireEvent("clear", this);
19311 * Inserts Records to the Store at the given index and fires the add event.
19312 * @param {Number} index The start index at which to insert the passed Records.
19313 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19315 insert : function(index, records){
19316 records = [].concat(records);
19317 for(var i = 0, len = records.length; i < len; i++){
19318 this.data.insert(index, records[i]);
19319 records[i].join(this);
19321 this.fireEvent("add", this, records, index);
19325 * Get the index within the cache of the passed Record.
19326 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19327 * @return {Number} The index of the passed Record. Returns -1 if not found.
19329 indexOf : function(record){
19330 return this.data.indexOf(record);
19334 * Get the index within the cache of the Record with the passed id.
19335 * @param {String} id The id of the Record to find.
19336 * @return {Number} The index of the Record. Returns -1 if not found.
19338 indexOfId : function(id){
19339 return this.data.indexOfKey(id);
19343 * Get the Record with the specified id.
19344 * @param {String} id The id of the Record to find.
19345 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19347 getById : function(id){
19348 return this.data.key(id);
19352 * Get the Record at the specified index.
19353 * @param {Number} index The index of the Record to find.
19354 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19356 getAt : function(index){
19357 return this.data.itemAt(index);
19361 * Returns a range of Records between specified indices.
19362 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19363 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19364 * @return {Roo.data.Record[]} An array of Records
19366 getRange : function(start, end){
19367 return this.data.getRange(start, end);
19371 storeOptions : function(o){
19372 o = Roo.apply({}, o);
19375 this.lastOptions = o;
19379 * Loads the Record cache from the configured Proxy using the configured Reader.
19381 * If using remote paging, then the first load call must specify the <em>start</em>
19382 * and <em>limit</em> properties in the options.params property to establish the initial
19383 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19385 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19386 * and this call will return before the new data has been loaded. Perform any post-processing
19387 * in a callback function, or in a "load" event handler.</strong>
19389 * @param {Object} options An object containing properties which control loading options:<ul>
19390 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19391 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19392 * passed the following arguments:<ul>
19393 * <li>r : Roo.data.Record[]</li>
19394 * <li>options: Options object from the load call</li>
19395 * <li>success: Boolean success indicator</li></ul></li>
19396 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19397 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19400 load : function(options){
19401 options = options || {};
19402 if(this.fireEvent("beforeload", this, options) !== false){
19403 this.storeOptions(options);
19404 var p = Roo.apply(options.params || {}, this.baseParams);
19405 // if meta was not loaded from remote source.. try requesting it.
19406 if (!this.reader.metaFromRemote) {
19407 p._requestMeta = 1;
19409 if(this.sortInfo && this.remoteSort){
19410 var pn = this.paramNames;
19411 p[pn["sort"]] = this.sortInfo.field;
19412 p[pn["dir"]] = this.sortInfo.direction;
19414 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19419 * Reloads the Record cache from the configured Proxy using the configured Reader and
19420 * the options from the last load operation performed.
19421 * @param {Object} options (optional) An object containing properties which may override the options
19422 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19423 * the most recently used options are reused).
19425 reload : function(options){
19426 this.load(Roo.applyIf(options||{}, this.lastOptions));
19430 // Called as a callback by the Reader during a load operation.
19431 loadRecords : function(o, options, success){
19432 if(!o || success === false){
19433 if(success !== false){
19434 this.fireEvent("load", this, [], options);
19436 if(options.callback){
19437 options.callback.call(options.scope || this, [], options, false);
19441 // if data returned failure - throw an exception.
19442 if (o.success === false) {
19443 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19446 var r = o.records, t = o.totalRecords || r.length;
19447 if(!options || options.add !== true){
19448 if(this.pruneModifiedRecords){
19449 this.modified = [];
19451 for(var i = 0, len = r.length; i < len; i++){
19455 this.data = this.snapshot;
19456 delete this.snapshot;
19459 this.data.addAll(r);
19460 this.totalLength = t;
19462 this.fireEvent("datachanged", this);
19464 this.totalLength = Math.max(t, this.data.length+r.length);
19467 this.fireEvent("load", this, r, options);
19468 if(options.callback){
19469 options.callback.call(options.scope || this, r, options, true);
19474 * Loads data from a passed data block. A Reader which understands the format of the data
19475 * must have been configured in the constructor.
19476 * @param {Object} data The data block from which to read the Records. The format of the data expected
19477 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19478 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19480 loadData : function(o, append){
19481 var r = this.reader.readRecords(o);
19482 this.loadRecords(r, {add: append}, true);
19486 * Gets the number of cached records.
19488 * <em>If using paging, this may not be the total size of the dataset. If the data object
19489 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19490 * the data set size</em>
19492 getCount : function(){
19493 return this.data.length || 0;
19497 * Gets the total number of records in the dataset as returned by the server.
19499 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19500 * the dataset size</em>
19502 getTotalCount : function(){
19503 return this.totalLength || 0;
19507 * Returns the sort state of the Store as an object with two properties:
19509 field {String} The name of the field by which the Records are sorted
19510 direction {String} The sort order, "ASC" or "DESC"
19513 getSortState : function(){
19514 return this.sortInfo;
19518 applySort : function(){
19519 if(this.sortInfo && !this.remoteSort){
19520 var s = this.sortInfo, f = s.field;
19521 var st = this.fields.get(f).sortType;
19522 var fn = function(r1, r2){
19523 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19524 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19526 this.data.sort(s.direction, fn);
19527 if(this.snapshot && this.snapshot != this.data){
19528 this.snapshot.sort(s.direction, fn);
19534 * Sets the default sort column and order to be used by the next load operation.
19535 * @param {String} fieldName The name of the field to sort by.
19536 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19538 setDefaultSort : function(field, dir){
19539 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19543 * Sort the Records.
19544 * If remote sorting is used, the sort is performed on the server, and the cache is
19545 * reloaded. If local sorting is used, the cache is sorted internally.
19546 * @param {String} fieldName The name of the field to sort by.
19547 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19549 sort : function(fieldName, dir){
19550 var f = this.fields.get(fieldName);
19552 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19553 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19558 this.sortToggle[f.name] = dir;
19559 this.sortInfo = {field: f.name, direction: dir};
19560 if(!this.remoteSort){
19562 this.fireEvent("datachanged", this);
19564 this.load(this.lastOptions);
19569 * Calls the specified function for each of the Records in the cache.
19570 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19571 * Returning <em>false</em> aborts and exits the iteration.
19572 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19574 each : function(fn, scope){
19575 this.data.each(fn, scope);
19579 * Gets all records modified since the last commit. Modified records are persisted across load operations
19580 * (e.g., during paging).
19581 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19583 getModifiedRecords : function(){
19584 return this.modified;
19588 createFilterFn : function(property, value, anyMatch){
19589 if(!value.exec){ // not a regex
19590 value = String(value);
19591 if(value.length == 0){
19594 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19596 return function(r){
19597 return value.test(r.data[property]);
19602 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19603 * @param {String} property A field on your records
19604 * @param {Number} start The record index to start at (defaults to 0)
19605 * @param {Number} end The last record index to include (defaults to length - 1)
19606 * @return {Number} The sum
19608 sum : function(property, start, end){
19609 var rs = this.data.items, v = 0;
19610 start = start || 0;
19611 end = (end || end === 0) ? end : rs.length-1;
19613 for(var i = start; i <= end; i++){
19614 v += (rs[i].data[property] || 0);
19620 * Filter the records by a specified property.
19621 * @param {String} field A field on your records
19622 * @param {String/RegExp} value Either a string that the field
19623 * should start with or a RegExp to test against the field
19624 * @param {Boolean} anyMatch True to match any part not just the beginning
19626 filter : function(property, value, anyMatch){
19627 var fn = this.createFilterFn(property, value, anyMatch);
19628 return fn ? this.filterBy(fn) : this.clearFilter();
19632 * Filter by a function. The specified function will be called with each
19633 * record in this data source. If the function returns true the record is included,
19634 * otherwise it is filtered.
19635 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19636 * @param {Object} scope (optional) The scope of the function (defaults to this)
19638 filterBy : function(fn, scope){
19639 this.snapshot = this.snapshot || this.data;
19640 this.data = this.queryBy(fn, scope||this);
19641 this.fireEvent("datachanged", this);
19645 * Query the records by a specified property.
19646 * @param {String} field A field on your records
19647 * @param {String/RegExp} value Either a string that the field
19648 * should start with or a RegExp to test against the field
19649 * @param {Boolean} anyMatch True to match any part not just the beginning
19650 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19652 query : function(property, value, anyMatch){
19653 var fn = this.createFilterFn(property, value, anyMatch);
19654 return fn ? this.queryBy(fn) : this.data.clone();
19658 * Query by a function. The specified function will be called with each
19659 * record in this data source. If the function returns true the record is included
19661 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19662 * @param {Object} scope (optional) The scope of the function (defaults to this)
19663 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19665 queryBy : function(fn, scope){
19666 var data = this.snapshot || this.data;
19667 return data.filterBy(fn, scope||this);
19671 * Collects unique values for a particular dataIndex from this store.
19672 * @param {String} dataIndex The property to collect
19673 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19674 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19675 * @return {Array} An array of the unique values
19677 collect : function(dataIndex, allowNull, bypassFilter){
19678 var d = (bypassFilter === true && this.snapshot) ?
19679 this.snapshot.items : this.data.items;
19680 var v, sv, r = [], l = {};
19681 for(var i = 0, len = d.length; i < len; i++){
19682 v = d[i].data[dataIndex];
19684 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19693 * Revert to a view of the Record cache with no filtering applied.
19694 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19696 clearFilter : function(suppressEvent){
19697 if(this.snapshot && this.snapshot != this.data){
19698 this.data = this.snapshot;
19699 delete this.snapshot;
19700 if(suppressEvent !== true){
19701 this.fireEvent("datachanged", this);
19707 afterEdit : function(record){
19708 if(this.modified.indexOf(record) == -1){
19709 this.modified.push(record);
19711 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19715 afterReject : function(record){
19716 this.modified.remove(record);
19717 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19721 afterCommit : function(record){
19722 this.modified.remove(record);
19723 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19727 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19728 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19730 commitChanges : function(){
19731 var m = this.modified.slice(0);
19732 this.modified = [];
19733 for(var i = 0, len = m.length; i < len; i++){
19739 * Cancel outstanding changes on all changed records.
19741 rejectChanges : function(){
19742 var m = this.modified.slice(0);
19743 this.modified = [];
19744 for(var i = 0, len = m.length; i < len; i++){
19749 onMetaChange : function(meta, rtype, o){
19750 this.recordType = rtype;
19751 this.fields = rtype.prototype.fields;
19752 delete this.snapshot;
19753 this.sortInfo = meta.sortInfo || this.sortInfo;
19754 this.modified = [];
19755 this.fireEvent('metachange', this, this.reader.meta);
19759 * Ext JS Library 1.1.1
19760 * Copyright(c) 2006-2007, Ext JS, LLC.
19762 * Originally Released Under LGPL - original licence link has changed is not relivant.
19765 * <script type="text/javascript">
19769 * @class Roo.data.SimpleStore
19770 * @extends Roo.data.Store
19771 * Small helper class to make creating Stores from Array data easier.
19772 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19773 * @cfg {Array} fields An array of field definition objects, or field name strings.
19774 * @cfg {Array} data The multi-dimensional array of data
19776 * @param {Object} config
19778 Roo.data.SimpleStore = function(config){
19779 Roo.data.SimpleStore.superclass.constructor.call(this, {
19781 reader: new Roo.data.ArrayReader({
19784 Roo.data.Record.create(config.fields)
19786 proxy : new Roo.data.MemoryProxy(config.data)
19790 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19792 * Ext JS Library 1.1.1
19793 * Copyright(c) 2006-2007, Ext JS, LLC.
19795 * Originally Released Under LGPL - original licence link has changed is not relivant.
19798 * <script type="text/javascript">
19803 * @extends Roo.data.Store
19804 * @class Roo.data.JsonStore
19805 * Small helper class to make creating Stores for JSON data easier. <br/>
19807 var store = new Roo.data.JsonStore({
19808 url: 'get-images.php',
19810 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19813 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19814 * JsonReader and HttpProxy (unless inline data is provided).</b>
19815 * @cfg {Array} fields An array of field definition objects, or field name strings.
19817 * @param {Object} config
19819 Roo.data.JsonStore = function(c){
19820 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19821 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19822 reader: new Roo.data.JsonReader(c, c.fields)
19825 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19827 * Ext JS Library 1.1.1
19828 * Copyright(c) 2006-2007, Ext JS, LLC.
19830 * Originally Released Under LGPL - original licence link has changed is not relivant.
19833 * <script type="text/javascript">
19837 Roo.data.Field = function(config){
19838 if(typeof config == "string"){
19839 config = {name: config};
19841 Roo.apply(this, config);
19844 this.type = "auto";
19847 var st = Roo.data.SortTypes;
19848 // named sortTypes are supported, here we look them up
19849 if(typeof this.sortType == "string"){
19850 this.sortType = st[this.sortType];
19853 // set default sortType for strings and dates
19854 if(!this.sortType){
19857 this.sortType = st.asUCString;
19860 this.sortType = st.asDate;
19863 this.sortType = st.none;
19868 var stripRe = /[\$,%]/g;
19870 // prebuilt conversion function for this field, instead of
19871 // switching every time we're reading a value
19873 var cv, dateFormat = this.dateFormat;
19878 cv = function(v){ return v; };
19881 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19885 return v !== undefined && v !== null && v !== '' ?
19886 parseInt(String(v).replace(stripRe, ""), 10) : '';
19891 return v !== undefined && v !== null && v !== '' ?
19892 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19897 cv = function(v){ return v === true || v === "true" || v == 1; };
19904 if(v instanceof Date){
19908 if(dateFormat == "timestamp"){
19909 return new Date(v*1000);
19911 return Date.parseDate(v, dateFormat);
19913 var parsed = Date.parse(v);
19914 return parsed ? new Date(parsed) : null;
19923 Roo.data.Field.prototype = {
19931 * Ext JS Library 1.1.1
19932 * Copyright(c) 2006-2007, Ext JS, LLC.
19934 * Originally Released Under LGPL - original licence link has changed is not relivant.
19937 * <script type="text/javascript">
19940 // Base class for reading structured data from a data source. This class is intended to be
19941 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19944 * @class Roo.data.DataReader
19945 * Base class for reading structured data from a data source. This class is intended to be
19946 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19949 Roo.data.DataReader = function(meta, recordType){
19953 this.recordType = recordType instanceof Array ?
19954 Roo.data.Record.create(recordType) : recordType;
19957 Roo.data.DataReader.prototype = {
19959 * Create an empty record
19960 * @param {Object} data (optional) - overlay some values
19961 * @return {Roo.data.Record} record created.
19963 newRow : function(d) {
19965 this.recordType.prototype.fields.each(function(c) {
19967 case 'int' : da[c.name] = 0; break;
19968 case 'date' : da[c.name] = new Date(); break;
19969 case 'float' : da[c.name] = 0.0; break;
19970 case 'boolean' : da[c.name] = false; break;
19971 default : da[c.name] = ""; break;
19975 return new this.recordType(Roo.apply(da, d));
19980 * Ext JS Library 1.1.1
19981 * Copyright(c) 2006-2007, Ext JS, LLC.
19983 * Originally Released Under LGPL - original licence link has changed is not relivant.
19986 * <script type="text/javascript">
19990 * @class Roo.data.DataProxy
19991 * @extends Roo.data.Observable
19992 * This class is an abstract base class for implementations which provide retrieval of
19993 * unformatted data objects.<br>
19995 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19996 * (of the appropriate type which knows how to parse the data object) to provide a block of
19997 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19999 * Custom implementations must implement the load method as described in
20000 * {@link Roo.data.HttpProxy#load}.
20002 Roo.data.DataProxy = function(){
20005 * @event beforeload
20006 * Fires before a network request is made to retrieve a data object.
20007 * @param {Object} This DataProxy object.
20008 * @param {Object} params The params parameter to the load function.
20013 * Fires before the load method's callback is called.
20014 * @param {Object} This DataProxy object.
20015 * @param {Object} o The data object.
20016 * @param {Object} arg The callback argument object passed to the load function.
20020 * @event loadexception
20021 * Fires if an Exception occurs during data retrieval.
20022 * @param {Object} This DataProxy object.
20023 * @param {Object} o The data object.
20024 * @param {Object} arg The callback argument object passed to the load function.
20025 * @param {Object} e The Exception.
20027 loadexception : true
20029 Roo.data.DataProxy.superclass.constructor.call(this);
20032 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20035 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20039 * Ext JS Library 1.1.1
20040 * Copyright(c) 2006-2007, Ext JS, LLC.
20042 * Originally Released Under LGPL - original licence link has changed is not relivant.
20045 * <script type="text/javascript">
20048 * @class Roo.data.MemoryProxy
20049 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20050 * to the Reader when its load method is called.
20052 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20054 Roo.data.MemoryProxy = function(data){
20058 Roo.data.MemoryProxy.superclass.constructor.call(this);
20062 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20064 * Load data from the requested source (in this case an in-memory
20065 * data object passed to the constructor), read the data object into
20066 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20067 * process that block using the passed callback.
20068 * @param {Object} params This parameter is not used by the MemoryProxy class.
20069 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20070 * object into a block of Roo.data.Records.
20071 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20072 * The function must be passed <ul>
20073 * <li>The Record block object</li>
20074 * <li>The "arg" argument from the load function</li>
20075 * <li>A boolean success indicator</li>
20077 * @param {Object} scope The scope in which to call the callback
20078 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20080 load : function(params, reader, callback, scope, arg){
20081 params = params || {};
20084 result = reader.readRecords(this.data);
20086 this.fireEvent("loadexception", this, arg, null, e);
20087 callback.call(scope, null, arg, false);
20090 callback.call(scope, result, arg, true);
20094 update : function(params, records){
20099 * Ext JS Library 1.1.1
20100 * Copyright(c) 2006-2007, Ext JS, LLC.
20102 * Originally Released Under LGPL - original licence link has changed is not relivant.
20105 * <script type="text/javascript">
20108 * @class Roo.data.HttpProxy
20109 * @extends Roo.data.DataProxy
20110 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20111 * configured to reference a certain URL.<br><br>
20113 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20114 * from which the running page was served.<br><br>
20116 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20118 * Be aware that to enable the browser to parse an XML document, the server must set
20119 * the Content-Type header in the HTTP response to "text/xml".
20121 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20122 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20123 * will be used to make the request.
20125 Roo.data.HttpProxy = function(conn){
20126 Roo.data.HttpProxy.superclass.constructor.call(this);
20127 // is conn a conn config or a real conn?
20129 this.useAjax = !conn || !conn.events;
20133 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20134 // thse are take from connection...
20137 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20140 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20141 * extra parameters to each request made by this object. (defaults to undefined)
20144 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20145 * to each request made by this object. (defaults to undefined)
20148 * @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)
20151 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20154 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20160 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20164 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20165 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20166 * a finer-grained basis than the DataProxy events.
20168 getConnection : function(){
20169 return this.useAjax ? Roo.Ajax : this.conn;
20173 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20174 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20175 * process that block using the passed callback.
20176 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20177 * for the request to the remote server.
20178 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20179 * object into a block of Roo.data.Records.
20180 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20181 * The function must be passed <ul>
20182 * <li>The Record block object</li>
20183 * <li>The "arg" argument from the load function</li>
20184 * <li>A boolean success indicator</li>
20186 * @param {Object} scope The scope in which to call the callback
20187 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20189 load : function(params, reader, callback, scope, arg){
20190 if(this.fireEvent("beforeload", this, params) !== false){
20192 params : params || {},
20194 callback : callback,
20199 callback : this.loadResponse,
20203 Roo.applyIf(o, this.conn);
20204 if(this.activeRequest){
20205 Roo.Ajax.abort(this.activeRequest);
20207 this.activeRequest = Roo.Ajax.request(o);
20209 this.conn.request(o);
20212 callback.call(scope||this, null, arg, false);
20217 loadResponse : function(o, success, response){
20218 delete this.activeRequest;
20220 this.fireEvent("loadexception", this, o, response);
20221 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20226 result = o.reader.read(response);
20228 this.fireEvent("loadexception", this, o, response, e);
20229 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20233 this.fireEvent("load", this, o, o.request.arg);
20234 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20238 update : function(dataSet){
20243 updateResponse : function(dataSet){
20248 * Ext JS Library 1.1.1
20249 * Copyright(c) 2006-2007, Ext JS, LLC.
20251 * Originally Released Under LGPL - original licence link has changed is not relivant.
20254 * <script type="text/javascript">
20258 * @class Roo.data.ScriptTagProxy
20259 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20260 * other than the originating domain of the running page.<br><br>
20262 * <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
20263 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20265 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20266 * source code that is used as the source inside a <script> tag.<br><br>
20268 * In order for the browser to process the returned data, the server must wrap the data object
20269 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20270 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20271 * depending on whether the callback name was passed:
20274 boolean scriptTag = false;
20275 String cb = request.getParameter("callback");
20278 response.setContentType("text/javascript");
20280 response.setContentType("application/x-json");
20282 Writer out = response.getWriter();
20284 out.write(cb + "(");
20286 out.print(dataBlock.toJsonString());
20293 * @param {Object} config A configuration object.
20295 Roo.data.ScriptTagProxy = function(config){
20296 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20297 Roo.apply(this, config);
20298 this.head = document.getElementsByTagName("head")[0];
20301 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20303 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20305 * @cfg {String} url The URL from which to request the data object.
20308 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20312 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20313 * the server the name of the callback function set up by the load call to process the returned data object.
20314 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20315 * javascript output which calls this named function passing the data object as its only parameter.
20317 callbackParam : "callback",
20319 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20320 * name to the request.
20325 * Load data from the configured URL, read the data object into
20326 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20327 * process that block using the passed callback.
20328 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20329 * for the request to the remote server.
20330 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20331 * object into a block of Roo.data.Records.
20332 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20333 * The function must be passed <ul>
20334 * <li>The Record block object</li>
20335 * <li>The "arg" argument from the load function</li>
20336 * <li>A boolean success indicator</li>
20338 * @param {Object} scope The scope in which to call the callback
20339 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20341 load : function(params, reader, callback, scope, arg){
20342 if(this.fireEvent("beforeload", this, params) !== false){
20344 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20346 var url = this.url;
20347 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20349 url += "&_dc=" + (new Date().getTime());
20351 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20354 cb : "stcCallback"+transId,
20355 scriptId : "stcScript"+transId,
20359 callback : callback,
20365 window[trans.cb] = function(o){
20366 conn.handleResponse(o, trans);
20369 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20371 if(this.autoAbort !== false){
20375 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20377 var script = document.createElement("script");
20378 script.setAttribute("src", url);
20379 script.setAttribute("type", "text/javascript");
20380 script.setAttribute("id", trans.scriptId);
20381 this.head.appendChild(script);
20383 this.trans = trans;
20385 callback.call(scope||this, null, arg, false);
20390 isLoading : function(){
20391 return this.trans ? true : false;
20395 * Abort the current server request.
20397 abort : function(){
20398 if(this.isLoading()){
20399 this.destroyTrans(this.trans);
20404 destroyTrans : function(trans, isLoaded){
20405 this.head.removeChild(document.getElementById(trans.scriptId));
20406 clearTimeout(trans.timeoutId);
20408 window[trans.cb] = undefined;
20410 delete window[trans.cb];
20413 // if hasn't been loaded, wait for load to remove it to prevent script error
20414 window[trans.cb] = function(){
20415 window[trans.cb] = undefined;
20417 delete window[trans.cb];
20424 handleResponse : function(o, trans){
20425 this.trans = false;
20426 this.destroyTrans(trans, true);
20429 result = trans.reader.readRecords(o);
20431 this.fireEvent("loadexception", this, o, trans.arg, e);
20432 trans.callback.call(trans.scope||window, null, trans.arg, false);
20435 this.fireEvent("load", this, o, trans.arg);
20436 trans.callback.call(trans.scope||window, result, trans.arg, true);
20440 handleFailure : function(trans){
20441 this.trans = false;
20442 this.destroyTrans(trans, false);
20443 this.fireEvent("loadexception", this, null, trans.arg);
20444 trans.callback.call(trans.scope||window, null, trans.arg, false);
20448 * Ext JS Library 1.1.1
20449 * Copyright(c) 2006-2007, Ext JS, LLC.
20451 * Originally Released Under LGPL - original licence link has changed is not relivant.
20454 * <script type="text/javascript">
20458 * @class Roo.data.JsonReader
20459 * @extends Roo.data.DataReader
20460 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20461 * based on mappings in a provided Roo.data.Record constructor.
20463 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20464 * in the reply previously.
20469 var RecordDef = Roo.data.Record.create([
20470 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20471 {name: 'occupation'} // This field will use "occupation" as the mapping.
20473 var myReader = new Roo.data.JsonReader({
20474 totalProperty: "results", // The property which contains the total dataset size (optional)
20475 root: "rows", // The property which contains an Array of row objects
20476 id: "id" // The property within each row object that provides an ID for the record (optional)
20480 * This would consume a JSON file like this:
20482 { 'results': 2, 'rows': [
20483 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20484 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20487 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20488 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20489 * paged from the remote server.
20490 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20491 * @cfg {String} root name of the property which contains the Array of row objects.
20492 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20494 * Create a new JsonReader
20495 * @param {Object} meta Metadata configuration options
20496 * @param {Object} recordType Either an Array of field definition objects,
20497 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20499 Roo.data.JsonReader = function(meta, recordType){
20502 // set some defaults:
20503 Roo.applyIf(meta, {
20504 totalProperty: 'total',
20505 successProperty : 'success',
20510 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20512 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20515 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20516 * Used by Store query builder to append _requestMeta to params.
20519 metaFromRemote : false,
20521 * This method is only used by a DataProxy which has retrieved data from a remote server.
20522 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20523 * @return {Object} data A data block which is used by an Roo.data.Store object as
20524 * a cache of Roo.data.Records.
20526 read : function(response){
20527 var json = response.responseText;
20529 var o = /* eval:var:o */ eval("("+json+")");
20531 throw {message: "JsonReader.read: Json object not found"};
20537 this.metaFromRemote = true;
20538 this.meta = o.metaData;
20539 this.recordType = Roo.data.Record.create(o.metaData.fields);
20540 this.onMetaChange(this.meta, this.recordType, o);
20542 return this.readRecords(o);
20545 // private function a store will implement
20546 onMetaChange : function(meta, recordType, o){
20553 simpleAccess: function(obj, subsc) {
20560 getJsonAccessor: function(){
20562 return function(expr) {
20564 return(re.test(expr))
20565 ? new Function("obj", "return obj." + expr)
20570 return Roo.emptyFn;
20575 * Create a data block containing Roo.data.Records from an XML document.
20576 * @param {Object} o An object which contains an Array of row objects in the property specified
20577 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20578 * which contains the total size of the dataset.
20579 * @return {Object} data A data block which is used by an Roo.data.Store object as
20580 * a cache of Roo.data.Records.
20582 readRecords : function(o){
20584 * After any data loads, the raw JSON data is available for further custom processing.
20588 var s = this.meta, Record = this.recordType,
20589 f = Record.prototype.fields, fi = f.items, fl = f.length;
20591 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20593 if(s.totalProperty) {
20594 this.getTotal = this.getJsonAccessor(s.totalProperty);
20596 if(s.successProperty) {
20597 this.getSuccess = this.getJsonAccessor(s.successProperty);
20599 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20601 var g = this.getJsonAccessor(s.id);
20602 this.getId = function(rec) {
20604 return (r === undefined || r === "") ? null : r;
20607 this.getId = function(){return null;};
20610 for(var jj = 0; jj < fl; jj++){
20612 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20613 this.ef[jj] = this.getJsonAccessor(map);
20617 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20618 if(s.totalProperty){
20619 var vt = parseInt(this.getTotal(o), 10);
20624 if(s.successProperty){
20625 var vs = this.getSuccess(o);
20626 if(vs === false || vs === 'false'){
20631 for(var i = 0; i < c; i++){
20634 var id = this.getId(n);
20635 for(var j = 0; j < fl; j++){
20637 var v = this.ef[j](n);
20639 Roo.log('missing convert for ' + f.name);
20643 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20645 var record = new Record(values, id);
20647 records[i] = record;
20652 totalRecords : totalRecords
20657 * Ext JS Library 1.1.1
20658 * Copyright(c) 2006-2007, Ext JS, LLC.
20660 * Originally Released Under LGPL - original licence link has changed is not relivant.
20663 * <script type="text/javascript">
20667 * @class Roo.data.XmlReader
20668 * @extends Roo.data.DataReader
20669 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20670 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20672 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20673 * header in the HTTP response must be set to "text/xml".</em>
20677 var RecordDef = Roo.data.Record.create([
20678 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20679 {name: 'occupation'} // This field will use "occupation" as the mapping.
20681 var myReader = new Roo.data.XmlReader({
20682 totalRecords: "results", // The element which contains the total dataset size (optional)
20683 record: "row", // The repeated element which contains row information
20684 id: "id" // The element within the row that provides an ID for the record (optional)
20688 * This would consume an XML file like this:
20692 <results>2</results>
20695 <name>Bill</name>
20696 <occupation>Gardener</occupation>
20700 <name>Ben</name>
20701 <occupation>Horticulturalist</occupation>
20705 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20706 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20707 * paged from the remote server.
20708 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20709 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20710 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20711 * a record identifier value.
20713 * Create a new XmlReader
20714 * @param {Object} meta Metadata configuration options
20715 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20716 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20717 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20719 Roo.data.XmlReader = function(meta, recordType){
20721 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20723 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20725 * This method is only used by a DataProxy which has retrieved data from a remote server.
20726 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20727 * to contain a method called 'responseXML' that returns an XML document object.
20728 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20729 * a cache of Roo.data.Records.
20731 read : function(response){
20732 var doc = response.responseXML;
20734 throw {message: "XmlReader.read: XML Document not available"};
20736 return this.readRecords(doc);
20740 * Create a data block containing Roo.data.Records from an XML document.
20741 * @param {Object} doc A parsed XML document.
20742 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20743 * a cache of Roo.data.Records.
20745 readRecords : function(doc){
20747 * After any data loads/reads, the raw XML Document is available for further custom processing.
20748 * @type XMLDocument
20750 this.xmlData = doc;
20751 var root = doc.documentElement || doc;
20752 var q = Roo.DomQuery;
20753 var recordType = this.recordType, fields = recordType.prototype.fields;
20754 var sid = this.meta.id;
20755 var totalRecords = 0, success = true;
20756 if(this.meta.totalRecords){
20757 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20760 if(this.meta.success){
20761 var sv = q.selectValue(this.meta.success, root, true);
20762 success = sv !== false && sv !== 'false';
20765 var ns = q.select(this.meta.record, root);
20766 for(var i = 0, len = ns.length; i < len; i++) {
20769 var id = sid ? q.selectValue(sid, n) : undefined;
20770 for(var j = 0, jlen = fields.length; j < jlen; j++){
20771 var f = fields.items[j];
20772 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20774 values[f.name] = v;
20776 var record = new recordType(values, id);
20778 records[records.length] = record;
20784 totalRecords : totalRecords || records.length
20789 * Ext JS Library 1.1.1
20790 * Copyright(c) 2006-2007, Ext JS, LLC.
20792 * Originally Released Under LGPL - original licence link has changed is not relivant.
20795 * <script type="text/javascript">
20799 * @class Roo.data.ArrayReader
20800 * @extends Roo.data.DataReader
20801 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20802 * Each element of that Array represents a row of data fields. The
20803 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20804 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20808 var RecordDef = Roo.data.Record.create([
20809 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20810 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20812 var myReader = new Roo.data.ArrayReader({
20813 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20817 * This would consume an Array like this:
20819 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20821 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20823 * Create a new JsonReader
20824 * @param {Object} meta Metadata configuration options.
20825 * @param {Object} recordType Either an Array of field definition objects
20826 * as specified to {@link Roo.data.Record#create},
20827 * or an {@link Roo.data.Record} object
20828 * created using {@link Roo.data.Record#create}.
20830 Roo.data.ArrayReader = function(meta, recordType){
20831 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20834 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20836 * Create a data block containing Roo.data.Records from an XML document.
20837 * @param {Object} o An Array of row objects which represents the dataset.
20838 * @return {Object} data A data block which is used by an Roo.data.Store object as
20839 * a cache of Roo.data.Records.
20841 readRecords : function(o){
20842 var sid = this.meta ? this.meta.id : null;
20843 var recordType = this.recordType, fields = recordType.prototype.fields;
20846 for(var i = 0; i < root.length; i++){
20849 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20850 for(var j = 0, jlen = fields.length; j < jlen; j++){
20851 var f = fields.items[j];
20852 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20853 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20855 values[f.name] = v;
20857 var record = new recordType(values, id);
20859 records[records.length] = record;
20863 totalRecords : records.length
20868 * Ext JS Library 1.1.1
20869 * Copyright(c) 2006-2007, Ext JS, LLC.
20871 * Originally Released Under LGPL - original licence link has changed is not relivant.
20874 * <script type="text/javascript">
20879 * @class Roo.data.Tree
20880 * @extends Roo.util.Observable
20881 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20882 * in the tree have most standard DOM functionality.
20884 * @param {Node} root (optional) The root node
20886 Roo.data.Tree = function(root){
20887 this.nodeHash = {};
20889 * The root node for this tree
20894 this.setRootNode(root);
20899 * Fires when a new child node is appended to a node in this tree.
20900 * @param {Tree} tree The owner tree
20901 * @param {Node} parent The parent node
20902 * @param {Node} node The newly appended node
20903 * @param {Number} index The index of the newly appended node
20908 * Fires when a child node is removed from a node in this tree.
20909 * @param {Tree} tree The owner tree
20910 * @param {Node} parent The parent node
20911 * @param {Node} node The child node removed
20916 * Fires when a node is moved to a new location in the tree
20917 * @param {Tree} tree The owner tree
20918 * @param {Node} node The node moved
20919 * @param {Node} oldParent The old parent of this node
20920 * @param {Node} newParent The new parent of this node
20921 * @param {Number} index The index it was moved to
20926 * Fires when a new child node is inserted in a node in this tree.
20927 * @param {Tree} tree The owner tree
20928 * @param {Node} parent The parent node
20929 * @param {Node} node The child node inserted
20930 * @param {Node} refNode The child node the node was inserted before
20934 * @event beforeappend
20935 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20936 * @param {Tree} tree The owner tree
20937 * @param {Node} parent The parent node
20938 * @param {Node} node The child node to be appended
20940 "beforeappend" : true,
20942 * @event beforeremove
20943 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20944 * @param {Tree} tree The owner tree
20945 * @param {Node} parent The parent node
20946 * @param {Node} node The child node to be removed
20948 "beforeremove" : true,
20950 * @event beforemove
20951 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20952 * @param {Tree} tree The owner tree
20953 * @param {Node} node The node being moved
20954 * @param {Node} oldParent The parent of the node
20955 * @param {Node} newParent The new parent the node is moving to
20956 * @param {Number} index The index it is being moved to
20958 "beforemove" : true,
20960 * @event beforeinsert
20961 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20962 * @param {Tree} tree The owner tree
20963 * @param {Node} parent The parent node
20964 * @param {Node} node The child node to be inserted
20965 * @param {Node} refNode The child node the node is being inserted before
20967 "beforeinsert" : true
20970 Roo.data.Tree.superclass.constructor.call(this);
20973 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20974 pathSeparator: "/",
20976 proxyNodeEvent : function(){
20977 return this.fireEvent.apply(this, arguments);
20981 * Returns the root node for this tree.
20984 getRootNode : function(){
20989 * Sets the root node for this tree.
20990 * @param {Node} node
20993 setRootNode : function(node){
20995 node.ownerTree = this;
20996 node.isRoot = true;
20997 this.registerNode(node);
21002 * Gets a node in this tree by its id.
21003 * @param {String} id
21006 getNodeById : function(id){
21007 return this.nodeHash[id];
21010 registerNode : function(node){
21011 this.nodeHash[node.id] = node;
21014 unregisterNode : function(node){
21015 delete this.nodeHash[node.id];
21018 toString : function(){
21019 return "[Tree"+(this.id?" "+this.id:"")+"]";
21024 * @class Roo.data.Node
21025 * @extends Roo.util.Observable
21026 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21027 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21029 * @param {Object} attributes The attributes/config for the node
21031 Roo.data.Node = function(attributes){
21033 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21036 this.attributes = attributes || {};
21037 this.leaf = this.attributes.leaf;
21039 * The node id. @type String
21041 this.id = this.attributes.id;
21043 this.id = Roo.id(null, "ynode-");
21044 this.attributes.id = this.id;
21047 * All child nodes of this node. @type Array
21049 this.childNodes = [];
21050 if(!this.childNodes.indexOf){ // indexOf is a must
21051 this.childNodes.indexOf = function(o){
21052 for(var i = 0, len = this.length; i < len; i++){
21061 * The parent node for this node. @type Node
21063 this.parentNode = null;
21065 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21067 this.firstChild = null;
21069 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21071 this.lastChild = null;
21073 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21075 this.previousSibling = null;
21077 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21079 this.nextSibling = null;
21084 * Fires when a new child node is appended
21085 * @param {Tree} tree The owner tree
21086 * @param {Node} this This node
21087 * @param {Node} node The newly appended node
21088 * @param {Number} index The index of the newly appended node
21093 * Fires when a child node is removed
21094 * @param {Tree} tree The owner tree
21095 * @param {Node} this This node
21096 * @param {Node} node The removed node
21101 * Fires when this node is moved to a new location in the tree
21102 * @param {Tree} tree The owner tree
21103 * @param {Node} this This node
21104 * @param {Node} oldParent The old parent of this node
21105 * @param {Node} newParent The new parent of this node
21106 * @param {Number} index The index it was moved to
21111 * Fires when a new child node is inserted.
21112 * @param {Tree} tree The owner tree
21113 * @param {Node} this This node
21114 * @param {Node} node The child node inserted
21115 * @param {Node} refNode The child node the node was inserted before
21119 * @event beforeappend
21120 * Fires before a new child is appended, return false to cancel the append.
21121 * @param {Tree} tree The owner tree
21122 * @param {Node} this This node
21123 * @param {Node} node The child node to be appended
21125 "beforeappend" : true,
21127 * @event beforeremove
21128 * Fires before a child is removed, return false to cancel the remove.
21129 * @param {Tree} tree The owner tree
21130 * @param {Node} this This node
21131 * @param {Node} node The child node to be removed
21133 "beforeremove" : true,
21135 * @event beforemove
21136 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21137 * @param {Tree} tree The owner tree
21138 * @param {Node} this This node
21139 * @param {Node} oldParent The parent of this node
21140 * @param {Node} newParent The new parent this node is moving to
21141 * @param {Number} index The index it is being moved to
21143 "beforemove" : true,
21145 * @event beforeinsert
21146 * Fires before a new child is inserted, return false to cancel the insert.
21147 * @param {Tree} tree The owner tree
21148 * @param {Node} this This node
21149 * @param {Node} node The child node to be inserted
21150 * @param {Node} refNode The child node the node is being inserted before
21152 "beforeinsert" : true
21154 this.listeners = this.attributes.listeners;
21155 Roo.data.Node.superclass.constructor.call(this);
21158 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21159 fireEvent : function(evtName){
21160 // first do standard event for this node
21161 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21164 // then bubble it up to the tree if the event wasn't cancelled
21165 var ot = this.getOwnerTree();
21167 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21175 * Returns true if this node is a leaf
21176 * @return {Boolean}
21178 isLeaf : function(){
21179 return this.leaf === true;
21183 setFirstChild : function(node){
21184 this.firstChild = node;
21188 setLastChild : function(node){
21189 this.lastChild = node;
21194 * Returns true if this node is the last child of its parent
21195 * @return {Boolean}
21197 isLast : function(){
21198 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21202 * Returns true if this node is the first child of its parent
21203 * @return {Boolean}
21205 isFirst : function(){
21206 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21209 hasChildNodes : function(){
21210 return !this.isLeaf() && this.childNodes.length > 0;
21214 * Insert node(s) as the last child node of this node.
21215 * @param {Node/Array} node The node or Array of nodes to append
21216 * @return {Node} The appended node if single append, or null if an array was passed
21218 appendChild : function(node){
21220 if(node instanceof Array){
21222 }else if(arguments.length > 1){
21225 // if passed an array or multiple args do them one by one
21227 for(var i = 0, len = multi.length; i < len; i++) {
21228 this.appendChild(multi[i]);
21231 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21234 var index = this.childNodes.length;
21235 var oldParent = node.parentNode;
21236 // it's a move, make sure we move it cleanly
21238 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21241 oldParent.removeChild(node);
21243 index = this.childNodes.length;
21245 this.setFirstChild(node);
21247 this.childNodes.push(node);
21248 node.parentNode = this;
21249 var ps = this.childNodes[index-1];
21251 node.previousSibling = ps;
21252 ps.nextSibling = node;
21254 node.previousSibling = null;
21256 node.nextSibling = null;
21257 this.setLastChild(node);
21258 node.setOwnerTree(this.getOwnerTree());
21259 this.fireEvent("append", this.ownerTree, this, node, index);
21261 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21268 * Removes a child node from this node.
21269 * @param {Node} node The node to remove
21270 * @return {Node} The removed node
21272 removeChild : function(node){
21273 var index = this.childNodes.indexOf(node);
21277 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21281 // remove it from childNodes collection
21282 this.childNodes.splice(index, 1);
21285 if(node.previousSibling){
21286 node.previousSibling.nextSibling = node.nextSibling;
21288 if(node.nextSibling){
21289 node.nextSibling.previousSibling = node.previousSibling;
21292 // update child refs
21293 if(this.firstChild == node){
21294 this.setFirstChild(node.nextSibling);
21296 if(this.lastChild == node){
21297 this.setLastChild(node.previousSibling);
21300 node.setOwnerTree(null);
21301 // clear any references from the node
21302 node.parentNode = null;
21303 node.previousSibling = null;
21304 node.nextSibling = null;
21305 this.fireEvent("remove", this.ownerTree, this, node);
21310 * Inserts the first node before the second node in this nodes childNodes collection.
21311 * @param {Node} node The node to insert
21312 * @param {Node} refNode The node to insert before (if null the node is appended)
21313 * @return {Node} The inserted node
21315 insertBefore : function(node, refNode){
21316 if(!refNode){ // like standard Dom, refNode can be null for append
21317 return this.appendChild(node);
21320 if(node == refNode){
21324 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21327 var index = this.childNodes.indexOf(refNode);
21328 var oldParent = node.parentNode;
21329 var refIndex = index;
21331 // when moving internally, indexes will change after remove
21332 if(oldParent == this && this.childNodes.indexOf(node) < index){
21336 // it's a move, make sure we move it cleanly
21338 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21341 oldParent.removeChild(node);
21344 this.setFirstChild(node);
21346 this.childNodes.splice(refIndex, 0, node);
21347 node.parentNode = this;
21348 var ps = this.childNodes[refIndex-1];
21350 node.previousSibling = ps;
21351 ps.nextSibling = node;
21353 node.previousSibling = null;
21355 node.nextSibling = refNode;
21356 refNode.previousSibling = node;
21357 node.setOwnerTree(this.getOwnerTree());
21358 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21360 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21366 * Returns the child node at the specified index.
21367 * @param {Number} index
21370 item : function(index){
21371 return this.childNodes[index];
21375 * Replaces one child node in this node with another.
21376 * @param {Node} newChild The replacement node
21377 * @param {Node} oldChild The node to replace
21378 * @return {Node} The replaced node
21380 replaceChild : function(newChild, oldChild){
21381 this.insertBefore(newChild, oldChild);
21382 this.removeChild(oldChild);
21387 * Returns the index of a child node
21388 * @param {Node} node
21389 * @return {Number} The index of the node or -1 if it was not found
21391 indexOf : function(child){
21392 return this.childNodes.indexOf(child);
21396 * Returns the tree this node is in.
21399 getOwnerTree : function(){
21400 // if it doesn't have one, look for one
21401 if(!this.ownerTree){
21405 this.ownerTree = p.ownerTree;
21411 return this.ownerTree;
21415 * Returns depth of this node (the root node has a depth of 0)
21418 getDepth : function(){
21421 while(p.parentNode){
21429 setOwnerTree : function(tree){
21430 // if it's move, we need to update everyone
21431 if(tree != this.ownerTree){
21432 if(this.ownerTree){
21433 this.ownerTree.unregisterNode(this);
21435 this.ownerTree = tree;
21436 var cs = this.childNodes;
21437 for(var i = 0, len = cs.length; i < len; i++) {
21438 cs[i].setOwnerTree(tree);
21441 tree.registerNode(this);
21447 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21448 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21449 * @return {String} The path
21451 getPath : function(attr){
21452 attr = attr || "id";
21453 var p = this.parentNode;
21454 var b = [this.attributes[attr]];
21456 b.unshift(p.attributes[attr]);
21459 var sep = this.getOwnerTree().pathSeparator;
21460 return sep + b.join(sep);
21464 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21465 * function call will be the scope provided or the current node. The arguments to the function
21466 * will be the args provided or the current node. If the function returns false at any point,
21467 * the bubble is stopped.
21468 * @param {Function} fn The function to call
21469 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21470 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21472 bubble : function(fn, scope, args){
21475 if(fn.call(scope || p, args || p) === false){
21483 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21484 * function call will be the scope provided or the current node. The arguments to the function
21485 * will be the args provided or the current node. If the function returns false at any point,
21486 * the cascade is stopped on that branch.
21487 * @param {Function} fn The function to call
21488 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21489 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21491 cascade : function(fn, scope, args){
21492 if(fn.call(scope || this, args || this) !== false){
21493 var cs = this.childNodes;
21494 for(var i = 0, len = cs.length; i < len; i++) {
21495 cs[i].cascade(fn, scope, args);
21501 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21502 * function call will be the scope provided or the current node. The arguments to the function
21503 * will be the args provided or the current node. If the function returns false at any point,
21504 * the iteration stops.
21505 * @param {Function} fn The function to call
21506 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21507 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21509 eachChild : function(fn, scope, args){
21510 var cs = this.childNodes;
21511 for(var i = 0, len = cs.length; i < len; i++) {
21512 if(fn.call(scope || this, args || cs[i]) === false){
21519 * Finds the first child that has the attribute with the specified value.
21520 * @param {String} attribute The attribute name
21521 * @param {Mixed} value The value to search for
21522 * @return {Node} The found child or null if none was found
21524 findChild : function(attribute, value){
21525 var cs = this.childNodes;
21526 for(var i = 0, len = cs.length; i < len; i++) {
21527 if(cs[i].attributes[attribute] == value){
21535 * Finds the first child by a custom function. The child matches if the function passed
21537 * @param {Function} fn
21538 * @param {Object} scope (optional)
21539 * @return {Node} The found child or null if none was found
21541 findChildBy : function(fn, scope){
21542 var cs = this.childNodes;
21543 for(var i = 0, len = cs.length; i < len; i++) {
21544 if(fn.call(scope||cs[i], cs[i]) === true){
21552 * Sorts this nodes children using the supplied sort function
21553 * @param {Function} fn
21554 * @param {Object} scope (optional)
21556 sort : function(fn, scope){
21557 var cs = this.childNodes;
21558 var len = cs.length;
21560 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21562 for(var i = 0; i < len; i++){
21564 n.previousSibling = cs[i-1];
21565 n.nextSibling = cs[i+1];
21567 this.setFirstChild(n);
21570 this.setLastChild(n);
21577 * Returns true if this node is an ancestor (at any point) of the passed node.
21578 * @param {Node} node
21579 * @return {Boolean}
21581 contains : function(node){
21582 return node.isAncestor(this);
21586 * Returns true if the passed node is an ancestor (at any point) of this node.
21587 * @param {Node} node
21588 * @return {Boolean}
21590 isAncestor : function(node){
21591 var p = this.parentNode;
21601 toString : function(){
21602 return "[Node"+(this.id?" "+this.id:"")+"]";
21606 * Ext JS Library 1.1.1
21607 * Copyright(c) 2006-2007, Ext JS, LLC.
21609 * Originally Released Under LGPL - original licence link has changed is not relivant.
21612 * <script type="text/javascript">
21617 * @class Roo.ComponentMgr
21618 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21621 Roo.ComponentMgr = function(){
21622 var all = new Roo.util.MixedCollection();
21626 * Registers a component.
21627 * @param {Roo.Component} c The component
21629 register : function(c){
21634 * Unregisters a component.
21635 * @param {Roo.Component} c The component
21637 unregister : function(c){
21642 * Returns a component by id
21643 * @param {String} id The component id
21645 get : function(id){
21646 return all.get(id);
21650 * Registers a function that will be called when a specified component is added to ComponentMgr
21651 * @param {String} id The component id
21652 * @param {Funtction} fn The callback function
21653 * @param {Object} scope The scope of the callback
21655 onAvailable : function(id, fn, scope){
21656 all.on("add", function(index, o){
21658 fn.call(scope || o, o);
21659 all.un("add", fn, scope);
21666 * Ext JS Library 1.1.1
21667 * Copyright(c) 2006-2007, Ext JS, LLC.
21669 * Originally Released Under LGPL - original licence link has changed is not relivant.
21672 * <script type="text/javascript">
21676 * @class Roo.Component
21677 * @extends Roo.util.Observable
21678 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21679 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21680 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21681 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21682 * All visual components (widgets) that require rendering into a layout should subclass Component.
21684 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21685 * 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
21686 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21688 Roo.Component = function(config){
21689 config = config || {};
21690 if(config.tagName || config.dom || typeof config == "string"){ // element object
21691 config = {el: config, id: config.id || config};
21693 this.initialConfig = config;
21695 Roo.apply(this, config);
21699 * Fires after the component is disabled.
21700 * @param {Roo.Component} this
21705 * Fires after the component is enabled.
21706 * @param {Roo.Component} this
21710 * @event beforeshow
21711 * Fires before the component is shown. Return false to stop the show.
21712 * @param {Roo.Component} this
21717 * Fires after the component is shown.
21718 * @param {Roo.Component} this
21722 * @event beforehide
21723 * Fires before the component is hidden. Return false to stop the hide.
21724 * @param {Roo.Component} this
21729 * Fires after the component is hidden.
21730 * @param {Roo.Component} this
21734 * @event beforerender
21735 * Fires before the component is rendered. Return false to stop the render.
21736 * @param {Roo.Component} this
21738 beforerender : true,
21741 * Fires after the component is rendered.
21742 * @param {Roo.Component} this
21746 * @event beforedestroy
21747 * Fires before the component is destroyed. Return false to stop the destroy.
21748 * @param {Roo.Component} this
21750 beforedestroy : true,
21753 * Fires after the component is destroyed.
21754 * @param {Roo.Component} this
21759 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21761 Roo.ComponentMgr.register(this);
21762 Roo.Component.superclass.constructor.call(this);
21763 this.initComponent();
21764 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21765 this.render(this.renderTo);
21766 delete this.renderTo;
21771 Roo.Component.AUTO_ID = 1000;
21773 Roo.extend(Roo.Component, Roo.util.Observable, {
21775 * @property {Boolean} hidden
21776 * true if this component is hidden. Read-only.
21780 * true if this component is disabled. Read-only.
21784 * true if this component has been rendered. Read-only.
21788 /** @cfg {String} disableClass
21789 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21791 disabledClass : "x-item-disabled",
21792 /** @cfg {Boolean} allowDomMove
21793 * Whether the component can move the Dom node when rendering (defaults to true).
21795 allowDomMove : true,
21796 /** @cfg {String} hideMode
21797 * How this component should hidden. Supported values are
21798 * "visibility" (css visibility), "offsets" (negative offset position) and
21799 * "display" (css display) - defaults to "display".
21801 hideMode: 'display',
21804 ctype : "Roo.Component",
21806 /** @cfg {String} actionMode
21807 * which property holds the element that used for hide() / show() / disable() / enable()
21813 getActionEl : function(){
21814 return this[this.actionMode];
21817 initComponent : Roo.emptyFn,
21819 * If this is a lazy rendering component, render it to its container element.
21820 * @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.
21822 render : function(container, position){
21823 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21824 if(!container && this.el){
21825 this.el = Roo.get(this.el);
21826 container = this.el.dom.parentNode;
21827 this.allowDomMove = false;
21829 this.container = Roo.get(container);
21830 this.rendered = true;
21831 if(position !== undefined){
21832 if(typeof position == 'number'){
21833 position = this.container.dom.childNodes[position];
21835 position = Roo.getDom(position);
21838 this.onRender(this.container, position || null);
21840 this.el.addClass(this.cls);
21844 this.el.applyStyles(this.style);
21847 this.fireEvent("render", this);
21848 this.afterRender(this.container);
21860 // default function is not really useful
21861 onRender : function(ct, position){
21863 this.el = Roo.get(this.el);
21864 if(this.allowDomMove !== false){
21865 ct.dom.insertBefore(this.el.dom, position);
21871 getAutoCreate : function(){
21872 var cfg = typeof this.autoCreate == "object" ?
21873 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21874 if(this.id && !cfg.id){
21881 afterRender : Roo.emptyFn,
21884 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21885 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21887 destroy : function(){
21888 if(this.fireEvent("beforedestroy", this) !== false){
21889 this.purgeListeners();
21890 this.beforeDestroy();
21892 this.el.removeAllListeners();
21894 if(this.actionMode == "container"){
21895 this.container.remove();
21899 Roo.ComponentMgr.unregister(this);
21900 this.fireEvent("destroy", this);
21905 beforeDestroy : function(){
21910 onDestroy : function(){
21915 * Returns the underlying {@link Roo.Element}.
21916 * @return {Roo.Element} The element
21918 getEl : function(){
21923 * Returns the id of this component.
21926 getId : function(){
21931 * Try to focus this component.
21932 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21933 * @return {Roo.Component} this
21935 focus : function(selectText){
21938 if(selectText === true){
21939 this.el.dom.select();
21954 * Disable this component.
21955 * @return {Roo.Component} this
21957 disable : function(){
21961 this.disabled = true;
21962 this.fireEvent("disable", this);
21967 onDisable : function(){
21968 this.getActionEl().addClass(this.disabledClass);
21969 this.el.dom.disabled = true;
21973 * Enable this component.
21974 * @return {Roo.Component} this
21976 enable : function(){
21980 this.disabled = false;
21981 this.fireEvent("enable", this);
21986 onEnable : function(){
21987 this.getActionEl().removeClass(this.disabledClass);
21988 this.el.dom.disabled = false;
21992 * Convenience function for setting disabled/enabled by boolean.
21993 * @param {Boolean} disabled
21995 setDisabled : function(disabled){
21996 this[disabled ? "disable" : "enable"]();
22000 * Show this component.
22001 * @return {Roo.Component} this
22004 if(this.fireEvent("beforeshow", this) !== false){
22005 this.hidden = false;
22009 this.fireEvent("show", this);
22015 onShow : function(){
22016 var ae = this.getActionEl();
22017 if(this.hideMode == 'visibility'){
22018 ae.dom.style.visibility = "visible";
22019 }else if(this.hideMode == 'offsets'){
22020 ae.removeClass('x-hidden');
22022 ae.dom.style.display = "";
22027 * Hide this component.
22028 * @return {Roo.Component} this
22031 if(this.fireEvent("beforehide", this) !== false){
22032 this.hidden = true;
22036 this.fireEvent("hide", this);
22042 onHide : function(){
22043 var ae = this.getActionEl();
22044 if(this.hideMode == 'visibility'){
22045 ae.dom.style.visibility = "hidden";
22046 }else if(this.hideMode == 'offsets'){
22047 ae.addClass('x-hidden');
22049 ae.dom.style.display = "none";
22054 * Convenience function to hide or show this component by boolean.
22055 * @param {Boolean} visible True to show, false to hide
22056 * @return {Roo.Component} this
22058 setVisible: function(visible){
22068 * Returns true if this component is visible.
22070 isVisible : function(){
22071 return this.getActionEl().isVisible();
22074 cloneConfig : function(overrides){
22075 overrides = overrides || {};
22076 var id = overrides.id || Roo.id();
22077 var cfg = Roo.applyIf(overrides, this.initialConfig);
22078 cfg.id = id; // prevent dup id
22079 return new this.constructor(cfg);
22083 * Ext JS Library 1.1.1
22084 * Copyright(c) 2006-2007, Ext JS, LLC.
22086 * Originally Released Under LGPL - original licence link has changed is not relivant.
22089 * <script type="text/javascript">
22094 * @extends Roo.Element
22095 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22096 * automatic maintaining of shadow/shim positions.
22097 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22098 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22099 * you can pass a string with a CSS class name. False turns off the shadow.
22100 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22101 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22102 * @cfg {String} cls CSS class to add to the element
22103 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22104 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22106 * @param {Object} config An object with config options.
22107 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22110 Roo.Layer = function(config, existingEl){
22111 config = config || {};
22112 var dh = Roo.DomHelper;
22113 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22115 this.dom = Roo.getDom(existingEl);
22118 var o = config.dh || {tag: "div", cls: "x-layer"};
22119 this.dom = dh.append(pel, o);
22122 this.addClass(config.cls);
22124 this.constrain = config.constrain !== false;
22125 this.visibilityMode = Roo.Element.VISIBILITY;
22127 this.id = this.dom.id = config.id;
22129 this.id = Roo.id(this.dom);
22131 this.zindex = config.zindex || this.getZIndex();
22132 this.position("absolute", this.zindex);
22134 this.shadowOffset = config.shadowOffset || 4;
22135 this.shadow = new Roo.Shadow({
22136 offset : this.shadowOffset,
22137 mode : config.shadow
22140 this.shadowOffset = 0;
22142 this.useShim = config.shim !== false && Roo.useShims;
22143 this.useDisplay = config.useDisplay;
22147 var supr = Roo.Element.prototype;
22149 // shims are shared among layer to keep from having 100 iframes
22152 Roo.extend(Roo.Layer, Roo.Element, {
22154 getZIndex : function(){
22155 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22158 getShim : function(){
22165 var shim = shims.shift();
22167 shim = this.createShim();
22168 shim.enableDisplayMode('block');
22169 shim.dom.style.display = 'none';
22170 shim.dom.style.visibility = 'visible';
22172 var pn = this.dom.parentNode;
22173 if(shim.dom.parentNode != pn){
22174 pn.insertBefore(shim.dom, this.dom);
22176 shim.setStyle('z-index', this.getZIndex()-2);
22181 hideShim : function(){
22183 this.shim.setDisplayed(false);
22184 shims.push(this.shim);
22189 disableShadow : function(){
22191 this.shadowDisabled = true;
22192 this.shadow.hide();
22193 this.lastShadowOffset = this.shadowOffset;
22194 this.shadowOffset = 0;
22198 enableShadow : function(show){
22200 this.shadowDisabled = false;
22201 this.shadowOffset = this.lastShadowOffset;
22202 delete this.lastShadowOffset;
22210 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22211 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22212 sync : function(doShow){
22213 var sw = this.shadow;
22214 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22215 var sh = this.getShim();
22217 var w = this.getWidth(),
22218 h = this.getHeight();
22220 var l = this.getLeft(true),
22221 t = this.getTop(true);
22223 if(sw && !this.shadowDisabled){
22224 if(doShow && !sw.isVisible()){
22227 sw.realign(l, t, w, h);
22233 // fit the shim behind the shadow, so it is shimmed too
22234 var a = sw.adjusts, s = sh.dom.style;
22235 s.left = (Math.min(l, l+a.l))+"px";
22236 s.top = (Math.min(t, t+a.t))+"px";
22237 s.width = (w+a.w)+"px";
22238 s.height = (h+a.h)+"px";
22245 sh.setLeftTop(l, t);
22252 destroy : function(){
22255 this.shadow.hide();
22257 this.removeAllListeners();
22258 var pn = this.dom.parentNode;
22260 pn.removeChild(this.dom);
22262 Roo.Element.uncache(this.id);
22265 remove : function(){
22270 beginUpdate : function(){
22271 this.updating = true;
22275 endUpdate : function(){
22276 this.updating = false;
22281 hideUnders : function(negOffset){
22283 this.shadow.hide();
22289 constrainXY : function(){
22290 if(this.constrain){
22291 var vw = Roo.lib.Dom.getViewWidth(),
22292 vh = Roo.lib.Dom.getViewHeight();
22293 var s = Roo.get(document).getScroll();
22295 var xy = this.getXY();
22296 var x = xy[0], y = xy[1];
22297 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22298 // only move it if it needs it
22300 // first validate right/bottom
22301 if((x + w) > vw+s.left){
22302 x = vw - w - this.shadowOffset;
22305 if((y + h) > vh+s.top){
22306 y = vh - h - this.shadowOffset;
22309 // then make sure top/left isn't negative
22320 var ay = this.avoidY;
22321 if(y <= ay && (y+h) >= ay){
22327 supr.setXY.call(this, xy);
22333 isVisible : function(){
22334 return this.visible;
22338 showAction : function(){
22339 this.visible = true; // track visibility to prevent getStyle calls
22340 if(this.useDisplay === true){
22341 this.setDisplayed("");
22342 }else if(this.lastXY){
22343 supr.setXY.call(this, this.lastXY);
22344 }else if(this.lastLT){
22345 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22350 hideAction : function(){
22351 this.visible = false;
22352 if(this.useDisplay === true){
22353 this.setDisplayed(false);
22355 this.setLeftTop(-10000,-10000);
22359 // overridden Element method
22360 setVisible : function(v, a, d, c, e){
22365 var cb = function(){
22370 }.createDelegate(this);
22371 supr.setVisible.call(this, true, true, d, cb, e);
22374 this.hideUnders(true);
22383 }.createDelegate(this);
22385 supr.setVisible.call(this, v, a, d, cb, e);
22394 storeXY : function(xy){
22395 delete this.lastLT;
22399 storeLeftTop : function(left, top){
22400 delete this.lastXY;
22401 this.lastLT = [left, top];
22405 beforeFx : function(){
22406 this.beforeAction();
22407 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22411 afterFx : function(){
22412 Roo.Layer.superclass.afterFx.apply(this, arguments);
22413 this.sync(this.isVisible());
22417 beforeAction : function(){
22418 if(!this.updating && this.shadow){
22419 this.shadow.hide();
22423 // overridden Element method
22424 setLeft : function(left){
22425 this.storeLeftTop(left, this.getTop(true));
22426 supr.setLeft.apply(this, arguments);
22430 setTop : function(top){
22431 this.storeLeftTop(this.getLeft(true), top);
22432 supr.setTop.apply(this, arguments);
22436 setLeftTop : function(left, top){
22437 this.storeLeftTop(left, top);
22438 supr.setLeftTop.apply(this, arguments);
22442 setXY : function(xy, a, d, c, e){
22444 this.beforeAction();
22446 var cb = this.createCB(c);
22447 supr.setXY.call(this, xy, a, d, cb, e);
22454 createCB : function(c){
22465 // overridden Element method
22466 setX : function(x, a, d, c, e){
22467 this.setXY([x, this.getY()], a, d, c, e);
22470 // overridden Element method
22471 setY : function(y, a, d, c, e){
22472 this.setXY([this.getX(), y], a, d, c, e);
22475 // overridden Element method
22476 setSize : function(w, h, a, d, c, e){
22477 this.beforeAction();
22478 var cb = this.createCB(c);
22479 supr.setSize.call(this, w, h, a, d, cb, e);
22485 // overridden Element method
22486 setWidth : function(w, a, d, c, e){
22487 this.beforeAction();
22488 var cb = this.createCB(c);
22489 supr.setWidth.call(this, w, a, d, cb, e);
22495 // overridden Element method
22496 setHeight : function(h, a, d, c, e){
22497 this.beforeAction();
22498 var cb = this.createCB(c);
22499 supr.setHeight.call(this, h, a, d, cb, e);
22505 // overridden Element method
22506 setBounds : function(x, y, w, h, a, d, c, e){
22507 this.beforeAction();
22508 var cb = this.createCB(c);
22510 this.storeXY([x, y]);
22511 supr.setXY.call(this, [x, y]);
22512 supr.setSize.call(this, w, h, a, d, cb, e);
22515 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22521 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22522 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22523 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22524 * @param {Number} zindex The new z-index to set
22525 * @return {this} The Layer
22527 setZIndex : function(zindex){
22528 this.zindex = zindex;
22529 this.setStyle("z-index", zindex + 2);
22531 this.shadow.setZIndex(zindex + 1);
22534 this.shim.setStyle("z-index", zindex);
22540 * Ext JS Library 1.1.1
22541 * Copyright(c) 2006-2007, Ext JS, LLC.
22543 * Originally Released Under LGPL - original licence link has changed is not relivant.
22546 * <script type="text/javascript">
22551 * @class Roo.Shadow
22552 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22553 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22554 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22556 * Create a new Shadow
22557 * @param {Object} config The config object
22559 Roo.Shadow = function(config){
22560 Roo.apply(this, config);
22561 if(typeof this.mode != "string"){
22562 this.mode = this.defaultMode;
22564 var o = this.offset, a = {h: 0};
22565 var rad = Math.floor(this.offset/2);
22566 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22572 a.l -= this.offset + rad;
22573 a.t -= this.offset + rad;
22584 a.l -= (this.offset - rad);
22585 a.t -= this.offset + rad;
22587 a.w -= (this.offset - rad)*2;
22598 a.l -= (this.offset - rad);
22599 a.t -= (this.offset - rad);
22601 a.w -= (this.offset + rad + 1);
22602 a.h -= (this.offset + rad);
22611 Roo.Shadow.prototype = {
22613 * @cfg {String} mode
22614 * The shadow display mode. Supports the following options:<br />
22615 * sides: Shadow displays on both sides and bottom only<br />
22616 * frame: Shadow displays equally on all four sides<br />
22617 * drop: Traditional bottom-right drop shadow (default)
22620 * @cfg {String} offset
22621 * The number of pixels to offset the shadow from the element (defaults to 4)
22626 defaultMode: "drop",
22629 * Displays the shadow under the target element
22630 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22632 show : function(target){
22633 target = Roo.get(target);
22635 this.el = Roo.Shadow.Pool.pull();
22636 if(this.el.dom.nextSibling != target.dom){
22637 this.el.insertBefore(target);
22640 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22642 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22645 target.getLeft(true),
22646 target.getTop(true),
22650 this.el.dom.style.display = "block";
22654 * Returns true if the shadow is visible, else false
22656 isVisible : function(){
22657 return this.el ? true : false;
22661 * Direct alignment when values are already available. Show must be called at least once before
22662 * calling this method to ensure it is initialized.
22663 * @param {Number} left The target element left position
22664 * @param {Number} top The target element top position
22665 * @param {Number} width The target element width
22666 * @param {Number} height The target element height
22668 realign : function(l, t, w, h){
22672 var a = this.adjusts, d = this.el.dom, s = d.style;
22674 s.left = (l+a.l)+"px";
22675 s.top = (t+a.t)+"px";
22676 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22678 if(s.width != sws || s.height != shs){
22682 var cn = d.childNodes;
22683 var sww = Math.max(0, (sw-12))+"px";
22684 cn[0].childNodes[1].style.width = sww;
22685 cn[1].childNodes[1].style.width = sww;
22686 cn[2].childNodes[1].style.width = sww;
22687 cn[1].style.height = Math.max(0, (sh-12))+"px";
22693 * Hides this shadow
22697 this.el.dom.style.display = "none";
22698 Roo.Shadow.Pool.push(this.el);
22704 * Adjust the z-index of this shadow
22705 * @param {Number} zindex The new z-index
22707 setZIndex : function(z){
22710 this.el.setStyle("z-index", z);
22715 // Private utility class that manages the internal Shadow cache
22716 Roo.Shadow.Pool = function(){
22718 var markup = Roo.isIE ?
22719 '<div class="x-ie-shadow"></div>' :
22720 '<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>';
22723 var sh = p.shift();
22725 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22726 sh.autoBoxAdjust = false;
22731 push : function(sh){
22737 * Ext JS Library 1.1.1
22738 * Copyright(c) 2006-2007, Ext JS, LLC.
22740 * Originally Released Under LGPL - original licence link has changed is not relivant.
22743 * <script type="text/javascript">
22747 * @class Roo.BoxComponent
22748 * @extends Roo.Component
22749 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22750 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22751 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22752 * layout containers.
22754 * @param {Roo.Element/String/Object} config The configuration options.
22756 Roo.BoxComponent = function(config){
22757 Roo.Component.call(this, config);
22761 * Fires after the component is resized.
22762 * @param {Roo.Component} this
22763 * @param {Number} adjWidth The box-adjusted width that was set
22764 * @param {Number} adjHeight The box-adjusted height that was set
22765 * @param {Number} rawWidth The width that was originally specified
22766 * @param {Number} rawHeight The height that was originally specified
22771 * Fires after the component is moved.
22772 * @param {Roo.Component} this
22773 * @param {Number} x The new x position
22774 * @param {Number} y The new y position
22780 Roo.extend(Roo.BoxComponent, Roo.Component, {
22781 // private, set in afterRender to signify that the component has been rendered
22783 // private, used to defer height settings to subclasses
22784 deferHeight: false,
22785 /** @cfg {Number} width
22786 * width (optional) size of component
22788 /** @cfg {Number} height
22789 * height (optional) size of component
22793 * Sets the width and height of the component. This method fires the resize event. This method can accept
22794 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22795 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22796 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22797 * @return {Roo.BoxComponent} this
22799 setSize : function(w, h){
22800 // support for standard size objects
22801 if(typeof w == 'object'){
22806 if(!this.boxReady){
22812 // prevent recalcs when not needed
22813 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22816 this.lastSize = {width: w, height: h};
22818 var adj = this.adjustSize(w, h);
22819 var aw = adj.width, ah = adj.height;
22820 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22821 var rz = this.getResizeEl();
22822 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22823 rz.setSize(aw, ah);
22824 }else if(!this.deferHeight && ah !== undefined){
22826 }else if(aw !== undefined){
22829 this.onResize(aw, ah, w, h);
22830 this.fireEvent('resize', this, aw, ah, w, h);
22836 * Gets the current size of the component's underlying element.
22837 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22839 getSize : function(){
22840 return this.el.getSize();
22844 * Gets the current XY position of the component's underlying element.
22845 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22846 * @return {Array} The XY position of the element (e.g., [100, 200])
22848 getPosition : function(local){
22849 if(local === true){
22850 return [this.el.getLeft(true), this.el.getTop(true)];
22852 return this.xy || this.el.getXY();
22856 * Gets the current box measurements of the component's underlying element.
22857 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22858 * @returns {Object} box An object in the format {x, y, width, height}
22860 getBox : function(local){
22861 var s = this.el.getSize();
22863 s.x = this.el.getLeft(true);
22864 s.y = this.el.getTop(true);
22866 var xy = this.xy || this.el.getXY();
22874 * Sets the current box measurements of the component's underlying element.
22875 * @param {Object} box An object in the format {x, y, width, height}
22876 * @returns {Roo.BoxComponent} this
22878 updateBox : function(box){
22879 this.setSize(box.width, box.height);
22880 this.setPagePosition(box.x, box.y);
22885 getResizeEl : function(){
22886 return this.resizeEl || this.el;
22890 getPositionEl : function(){
22891 return this.positionEl || this.el;
22895 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22896 * This method fires the move event.
22897 * @param {Number} left The new left
22898 * @param {Number} top The new top
22899 * @returns {Roo.BoxComponent} this
22901 setPosition : function(x, y){
22904 if(!this.boxReady){
22907 var adj = this.adjustPosition(x, y);
22908 var ax = adj.x, ay = adj.y;
22910 var el = this.getPositionEl();
22911 if(ax !== undefined || ay !== undefined){
22912 if(ax !== undefined && ay !== undefined){
22913 el.setLeftTop(ax, ay);
22914 }else if(ax !== undefined){
22916 }else if(ay !== undefined){
22919 this.onPosition(ax, ay);
22920 this.fireEvent('move', this, ax, ay);
22926 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22927 * This method fires the move event.
22928 * @param {Number} x The new x position
22929 * @param {Number} y The new y position
22930 * @returns {Roo.BoxComponent} this
22932 setPagePosition : function(x, y){
22935 if(!this.boxReady){
22938 if(x === undefined || y === undefined){ // cannot translate undefined points
22941 var p = this.el.translatePoints(x, y);
22942 this.setPosition(p.left, p.top);
22947 onRender : function(ct, position){
22948 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22950 this.resizeEl = Roo.get(this.resizeEl);
22952 if(this.positionEl){
22953 this.positionEl = Roo.get(this.positionEl);
22958 afterRender : function(){
22959 Roo.BoxComponent.superclass.afterRender.call(this);
22960 this.boxReady = true;
22961 this.setSize(this.width, this.height);
22962 if(this.x || this.y){
22963 this.setPosition(this.x, this.y);
22965 if(this.pageX || this.pageY){
22966 this.setPagePosition(this.pageX, this.pageY);
22971 * Force the component's size to recalculate based on the underlying element's current height and width.
22972 * @returns {Roo.BoxComponent} this
22974 syncSize : function(){
22975 delete this.lastSize;
22976 this.setSize(this.el.getWidth(), this.el.getHeight());
22981 * Called after the component is resized, this method is empty by default but can be implemented by any
22982 * subclass that needs to perform custom logic after a resize occurs.
22983 * @param {Number} adjWidth The box-adjusted width that was set
22984 * @param {Number} adjHeight The box-adjusted height that was set
22985 * @param {Number} rawWidth The width that was originally specified
22986 * @param {Number} rawHeight The height that was originally specified
22988 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22993 * Called after the component is moved, this method is empty by default but can be implemented by any
22994 * subclass that needs to perform custom logic after a move occurs.
22995 * @param {Number} x The new x position
22996 * @param {Number} y The new y position
22998 onPosition : function(x, y){
23003 adjustSize : function(w, h){
23004 if(this.autoWidth){
23007 if(this.autoHeight){
23010 return {width : w, height: h};
23014 adjustPosition : function(x, y){
23015 return {x : x, y: y};
23019 * Ext JS Library 1.1.1
23020 * Copyright(c) 2006-2007, Ext JS, LLC.
23022 * Originally Released Under LGPL - original licence link has changed is not relivant.
23025 * <script type="text/javascript">
23030 * @class Roo.SplitBar
23031 * @extends Roo.util.Observable
23032 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23036 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23037 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23038 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23039 split.minSize = 100;
23040 split.maxSize = 600;
23041 split.animate = true;
23042 split.on('moved', splitterMoved);
23045 * Create a new SplitBar
23046 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23047 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23048 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23049 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23050 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23051 position of the SplitBar).
23053 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23056 this.el = Roo.get(dragElement, true);
23057 this.el.dom.unselectable = "on";
23059 this.resizingEl = Roo.get(resizingElement, true);
23063 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23064 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23067 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23070 * The minimum size of the resizing element. (Defaults to 0)
23076 * The maximum size of the resizing element. (Defaults to 2000)
23079 this.maxSize = 2000;
23082 * Whether to animate the transition to the new size
23085 this.animate = false;
23088 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23091 this.useShim = false;
23096 if(!existingProxy){
23098 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23100 this.proxy = Roo.get(existingProxy).dom;
23103 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23106 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23109 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23112 this.dragSpecs = {};
23115 * @private The adapter to use to positon and resize elements
23117 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23118 this.adapter.init(this);
23120 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23122 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23123 this.el.addClass("x-splitbar-h");
23126 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23127 this.el.addClass("x-splitbar-v");
23133 * Fires when the splitter is moved (alias for {@link #event-moved})
23134 * @param {Roo.SplitBar} this
23135 * @param {Number} newSize the new width or height
23140 * Fires when the splitter is moved
23141 * @param {Roo.SplitBar} this
23142 * @param {Number} newSize the new width or height
23146 * @event beforeresize
23147 * Fires before the splitter is dragged
23148 * @param {Roo.SplitBar} this
23150 "beforeresize" : true,
23152 "beforeapply" : true
23155 Roo.util.Observable.call(this);
23158 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23159 onStartProxyDrag : function(x, y){
23160 this.fireEvent("beforeresize", this);
23162 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23164 o.enableDisplayMode("block");
23165 // all splitbars share the same overlay
23166 Roo.SplitBar.prototype.overlay = o;
23168 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23169 this.overlay.show();
23170 Roo.get(this.proxy).setDisplayed("block");
23171 var size = this.adapter.getElementSize(this);
23172 this.activeMinSize = this.getMinimumSize();;
23173 this.activeMaxSize = this.getMaximumSize();;
23174 var c1 = size - this.activeMinSize;
23175 var c2 = Math.max(this.activeMaxSize - size, 0);
23176 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23177 this.dd.resetConstraints();
23178 this.dd.setXConstraint(
23179 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23180 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23182 this.dd.setYConstraint(0, 0);
23184 this.dd.resetConstraints();
23185 this.dd.setXConstraint(0, 0);
23186 this.dd.setYConstraint(
23187 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23188 this.placement == Roo.SplitBar.TOP ? c2 : c1
23191 this.dragSpecs.startSize = size;
23192 this.dragSpecs.startPoint = [x, y];
23193 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23197 * @private Called after the drag operation by the DDProxy
23199 onEndProxyDrag : function(e){
23200 Roo.get(this.proxy).setDisplayed(false);
23201 var endPoint = Roo.lib.Event.getXY(e);
23203 this.overlay.hide();
23206 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23207 newSize = this.dragSpecs.startSize +
23208 (this.placement == Roo.SplitBar.LEFT ?
23209 endPoint[0] - this.dragSpecs.startPoint[0] :
23210 this.dragSpecs.startPoint[0] - endPoint[0]
23213 newSize = this.dragSpecs.startSize +
23214 (this.placement == Roo.SplitBar.TOP ?
23215 endPoint[1] - this.dragSpecs.startPoint[1] :
23216 this.dragSpecs.startPoint[1] - endPoint[1]
23219 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23220 if(newSize != this.dragSpecs.startSize){
23221 if(this.fireEvent('beforeapply', this, newSize) !== false){
23222 this.adapter.setElementSize(this, newSize);
23223 this.fireEvent("moved", this, newSize);
23224 this.fireEvent("resize", this, newSize);
23230 * Get the adapter this SplitBar uses
23231 * @return The adapter object
23233 getAdapter : function(){
23234 return this.adapter;
23238 * Set the adapter this SplitBar uses
23239 * @param {Object} adapter A SplitBar adapter object
23241 setAdapter : function(adapter){
23242 this.adapter = adapter;
23243 this.adapter.init(this);
23247 * Gets the minimum size for the resizing element
23248 * @return {Number} The minimum size
23250 getMinimumSize : function(){
23251 return this.minSize;
23255 * Sets the minimum size for the resizing element
23256 * @param {Number} minSize The minimum size
23258 setMinimumSize : function(minSize){
23259 this.minSize = minSize;
23263 * Gets the maximum size for the resizing element
23264 * @return {Number} The maximum size
23266 getMaximumSize : function(){
23267 return this.maxSize;
23271 * Sets the maximum size for the resizing element
23272 * @param {Number} maxSize The maximum size
23274 setMaximumSize : function(maxSize){
23275 this.maxSize = maxSize;
23279 * Sets the initialize size for the resizing element
23280 * @param {Number} size The initial size
23282 setCurrentSize : function(size){
23283 var oldAnimate = this.animate;
23284 this.animate = false;
23285 this.adapter.setElementSize(this, size);
23286 this.animate = oldAnimate;
23290 * Destroy this splitbar.
23291 * @param {Boolean} removeEl True to remove the element
23293 destroy : function(removeEl){
23295 this.shim.remove();
23298 this.proxy.parentNode.removeChild(this.proxy);
23306 * @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.
23308 Roo.SplitBar.createProxy = function(dir){
23309 var proxy = new Roo.Element(document.createElement("div"));
23310 proxy.unselectable();
23311 var cls = 'x-splitbar-proxy';
23312 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23313 document.body.appendChild(proxy.dom);
23318 * @class Roo.SplitBar.BasicLayoutAdapter
23319 * Default Adapter. It assumes the splitter and resizing element are not positioned
23320 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23322 Roo.SplitBar.BasicLayoutAdapter = function(){
23325 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23326 // do nothing for now
23327 init : function(s){
23331 * Called before drag operations to get the current size of the resizing element.
23332 * @param {Roo.SplitBar} s The SplitBar using this adapter
23334 getElementSize : function(s){
23335 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23336 return s.resizingEl.getWidth();
23338 return s.resizingEl.getHeight();
23343 * Called after drag operations to set the size of the resizing element.
23344 * @param {Roo.SplitBar} s The SplitBar using this adapter
23345 * @param {Number} newSize The new size to set
23346 * @param {Function} onComplete A function to be invoked when resizing is complete
23348 setElementSize : function(s, newSize, onComplete){
23349 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23351 s.resizingEl.setWidth(newSize);
23353 onComplete(s, newSize);
23356 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23361 s.resizingEl.setHeight(newSize);
23363 onComplete(s, newSize);
23366 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23373 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23374 * @extends Roo.SplitBar.BasicLayoutAdapter
23375 * Adapter that moves the splitter element to align with the resized sizing element.
23376 * Used with an absolute positioned SplitBar.
23377 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23378 * document.body, make sure you assign an id to the body element.
23380 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23381 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23382 this.container = Roo.get(container);
23385 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23386 init : function(s){
23387 this.basic.init(s);
23390 getElementSize : function(s){
23391 return this.basic.getElementSize(s);
23394 setElementSize : function(s, newSize, onComplete){
23395 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23398 moveSplitter : function(s){
23399 var yes = Roo.SplitBar;
23400 switch(s.placement){
23402 s.el.setX(s.resizingEl.getRight());
23405 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23408 s.el.setY(s.resizingEl.getBottom());
23411 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23418 * Orientation constant - Create a vertical SplitBar
23422 Roo.SplitBar.VERTICAL = 1;
23425 * Orientation constant - Create a horizontal SplitBar
23429 Roo.SplitBar.HORIZONTAL = 2;
23432 * Placement constant - The resizing element is to the left of the splitter element
23436 Roo.SplitBar.LEFT = 1;
23439 * Placement constant - The resizing element is to the right of the splitter element
23443 Roo.SplitBar.RIGHT = 2;
23446 * Placement constant - The resizing element is positioned above the splitter element
23450 Roo.SplitBar.TOP = 3;
23453 * Placement constant - The resizing element is positioned under splitter element
23457 Roo.SplitBar.BOTTOM = 4;
23460 * Ext JS Library 1.1.1
23461 * Copyright(c) 2006-2007, Ext JS, LLC.
23463 * Originally Released Under LGPL - original licence link has changed is not relivant.
23466 * <script type="text/javascript">
23471 * @extends Roo.util.Observable
23472 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23473 * This class also supports single and multi selection modes. <br>
23474 * Create a data model bound view:
23476 var store = new Roo.data.Store(...);
23478 var view = new Roo.View({
23480 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23482 singleSelect: true,
23483 selectedClass: "ydataview-selected",
23487 // listen for node click?
23488 view.on("click", function(vw, index, node, e){
23489 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23493 dataModel.load("foobar.xml");
23495 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23497 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23498 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23500 * Note: old style constructor is still suported (container, template, config)
23503 * Create a new View
23504 * @param {Object} config The config object
23507 Roo.View = function(config, depreciated_tpl, depreciated_config){
23509 if (typeof(depreciated_tpl) == 'undefined') {
23510 // new way.. - universal constructor.
23511 Roo.apply(this, config);
23512 this.el = Roo.get(this.el);
23515 this.el = Roo.get(config);
23516 this.tpl = depreciated_tpl;
23517 Roo.apply(this, depreciated_config);
23521 if(typeof(this.tpl) == "string"){
23522 this.tpl = new Roo.Template(this.tpl);
23524 // support xtype ctors..
23525 this.tpl = new Roo.factory(this.tpl, Roo);
23529 this.tpl.compile();
23536 * @event beforeclick
23537 * Fires before a click is processed. Returns false to cancel the default action.
23538 * @param {Roo.View} this
23539 * @param {Number} index The index of the target node
23540 * @param {HTMLElement} node The target node
23541 * @param {Roo.EventObject} e The raw event object
23543 "beforeclick" : true,
23546 * Fires when a template node is clicked.
23547 * @param {Roo.View} this
23548 * @param {Number} index The index of the target node
23549 * @param {HTMLElement} node The target node
23550 * @param {Roo.EventObject} e The raw event object
23555 * Fires when a template node is double clicked.
23556 * @param {Roo.View} this
23557 * @param {Number} index The index of the target node
23558 * @param {HTMLElement} node The target node
23559 * @param {Roo.EventObject} e The raw event object
23563 * @event contextmenu
23564 * Fires when a template node is right clicked.
23565 * @param {Roo.View} this
23566 * @param {Number} index The index of the target node
23567 * @param {HTMLElement} node The target node
23568 * @param {Roo.EventObject} e The raw event object
23570 "contextmenu" : true,
23572 * @event selectionchange
23573 * Fires when the selected nodes change.
23574 * @param {Roo.View} this
23575 * @param {Array} selections Array of the selected nodes
23577 "selectionchange" : true,
23580 * @event beforeselect
23581 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23582 * @param {Roo.View} this
23583 * @param {HTMLElement} node The node to be selected
23584 * @param {Array} selections Array of currently selected nodes
23586 "beforeselect" : true
23590 "click": this.onClick,
23591 "dblclick": this.onDblClick,
23592 "contextmenu": this.onContextMenu,
23596 this.selections = [];
23598 this.cmp = new Roo.CompositeElementLite([]);
23600 this.store = Roo.factory(this.store, Roo.data);
23601 this.setStore(this.store, true);
23603 Roo.View.superclass.constructor.call(this);
23606 Roo.extend(Roo.View, Roo.util.Observable, {
23609 * @cfg {Roo.data.Store} store Data store to load data from.
23614 * @cfg {String|Roo.Element} el The container element.
23619 * @cfg {String|Roo.Template} tpl The template used by this View
23624 * @cfg {String} selectedClass The css class to add to selected nodes
23626 selectedClass : "x-view-selected",
23628 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23632 * @cfg {Boolean} multiSelect Allow multiple selection
23635 multiSelect : false,
23637 * @cfg {Boolean} singleSelect Allow single selection
23639 singleSelect: false,
23642 * Returns the element this view is bound to.
23643 * @return {Roo.Element}
23645 getEl : function(){
23650 * Refreshes the view.
23652 refresh : function(){
23654 this.clearSelections();
23655 this.el.update("");
23657 var records = this.store.getRange();
23658 if(records.length < 1){
23659 this.el.update(this.emptyText);
23662 for(var i = 0, len = records.length; i < len; i++){
23663 var data = this.prepareData(records[i].data, i, records[i]);
23664 html[html.length] = t.apply(data);
23666 this.el.update(html.join(""));
23667 this.nodes = this.el.dom.childNodes;
23668 this.updateIndexes(0);
23672 * Function to override to reformat the data that is sent to
23673 * the template for each node.
23674 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23675 * a JSON object for an UpdateManager bound view).
23677 prepareData : function(data){
23681 onUpdate : function(ds, record){
23682 this.clearSelections();
23683 var index = this.store.indexOf(record);
23684 var n = this.nodes[index];
23685 this.tpl.insertBefore(n, this.prepareData(record.data));
23686 n.parentNode.removeChild(n);
23687 this.updateIndexes(index, index);
23690 onAdd : function(ds, records, index){
23691 this.clearSelections();
23692 if(this.nodes.length == 0){
23696 var n = this.nodes[index];
23697 for(var i = 0, len = records.length; i < len; i++){
23698 var d = this.prepareData(records[i].data);
23700 this.tpl.insertBefore(n, d);
23702 this.tpl.append(this.el, d);
23705 this.updateIndexes(index);
23708 onRemove : function(ds, record, index){
23709 this.clearSelections();
23710 this.el.dom.removeChild(this.nodes[index]);
23711 this.updateIndexes(index);
23715 * Refresh an individual node.
23716 * @param {Number} index
23718 refreshNode : function(index){
23719 this.onUpdate(this.store, this.store.getAt(index));
23722 updateIndexes : function(startIndex, endIndex){
23723 var ns = this.nodes;
23724 startIndex = startIndex || 0;
23725 endIndex = endIndex || ns.length - 1;
23726 for(var i = startIndex; i <= endIndex; i++){
23727 ns[i].nodeIndex = i;
23732 * Changes the data store this view uses and refresh the view.
23733 * @param {Store} store
23735 setStore : function(store, initial){
23736 if(!initial && this.store){
23737 this.store.un("datachanged", this.refresh);
23738 this.store.un("add", this.onAdd);
23739 this.store.un("remove", this.onRemove);
23740 this.store.un("update", this.onUpdate);
23741 this.store.un("clear", this.refresh);
23745 store.on("datachanged", this.refresh, this);
23746 store.on("add", this.onAdd, this);
23747 store.on("remove", this.onRemove, this);
23748 store.on("update", this.onUpdate, this);
23749 store.on("clear", this.refresh, this);
23758 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23759 * @param {HTMLElement} node
23760 * @return {HTMLElement} The template node
23762 findItemFromChild : function(node){
23763 var el = this.el.dom;
23764 if(!node || node.parentNode == el){
23767 var p = node.parentNode;
23768 while(p && p != el){
23769 if(p.parentNode == el){
23778 onClick : function(e){
23779 var item = this.findItemFromChild(e.getTarget());
23781 var index = this.indexOf(item);
23782 if(this.onItemClick(item, index, e) !== false){
23783 this.fireEvent("click", this, index, item, e);
23786 this.clearSelections();
23791 onContextMenu : function(e){
23792 var item = this.findItemFromChild(e.getTarget());
23794 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23799 onDblClick : function(e){
23800 var item = this.findItemFromChild(e.getTarget());
23802 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23806 onItemClick : function(item, index, e){
23807 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23810 if(this.multiSelect || this.singleSelect){
23811 if(this.multiSelect && e.shiftKey && this.lastSelection){
23812 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23814 this.select(item, this.multiSelect && e.ctrlKey);
23815 this.lastSelection = item;
23817 e.preventDefault();
23823 * Get the number of selected nodes.
23826 getSelectionCount : function(){
23827 return this.selections.length;
23831 * Get the currently selected nodes.
23832 * @return {Array} An array of HTMLElements
23834 getSelectedNodes : function(){
23835 return this.selections;
23839 * Get the indexes of the selected nodes.
23842 getSelectedIndexes : function(){
23843 var indexes = [], s = this.selections;
23844 for(var i = 0, len = s.length; i < len; i++){
23845 indexes.push(s[i].nodeIndex);
23851 * Clear all selections
23852 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23854 clearSelections : function(suppressEvent){
23855 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23856 this.cmp.elements = this.selections;
23857 this.cmp.removeClass(this.selectedClass);
23858 this.selections = [];
23859 if(!suppressEvent){
23860 this.fireEvent("selectionchange", this, this.selections);
23866 * Returns true if the passed node is selected
23867 * @param {HTMLElement/Number} node The node or node index
23868 * @return {Boolean}
23870 isSelected : function(node){
23871 var s = this.selections;
23875 node = this.getNode(node);
23876 return s.indexOf(node) !== -1;
23881 * @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
23882 * @param {Boolean} keepExisting (optional) true to keep existing selections
23883 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23885 select : function(nodeInfo, keepExisting, suppressEvent){
23886 if(nodeInfo instanceof Array){
23888 this.clearSelections(true);
23890 for(var i = 0, len = nodeInfo.length; i < len; i++){
23891 this.select(nodeInfo[i], true, true);
23894 var node = this.getNode(nodeInfo);
23895 if(node && !this.isSelected(node)){
23897 this.clearSelections(true);
23899 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23900 Roo.fly(node).addClass(this.selectedClass);
23901 this.selections.push(node);
23902 if(!suppressEvent){
23903 this.fireEvent("selectionchange", this, this.selections);
23911 * Gets a template node.
23912 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23913 * @return {HTMLElement} The node or null if it wasn't found
23915 getNode : function(nodeInfo){
23916 if(typeof nodeInfo == "string"){
23917 return document.getElementById(nodeInfo);
23918 }else if(typeof nodeInfo == "number"){
23919 return this.nodes[nodeInfo];
23925 * Gets a range template nodes.
23926 * @param {Number} startIndex
23927 * @param {Number} endIndex
23928 * @return {Array} An array of nodes
23930 getNodes : function(start, end){
23931 var ns = this.nodes;
23932 start = start || 0;
23933 end = typeof end == "undefined" ? ns.length - 1 : end;
23936 for(var i = start; i <= end; i++){
23940 for(var i = start; i >= end; i--){
23948 * Finds the index of the passed node
23949 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23950 * @return {Number} The index of the node or -1
23952 indexOf : function(node){
23953 node = this.getNode(node);
23954 if(typeof node.nodeIndex == "number"){
23955 return node.nodeIndex;
23957 var ns = this.nodes;
23958 for(var i = 0, len = ns.length; i < len; i++){
23968 * Ext JS Library 1.1.1
23969 * Copyright(c) 2006-2007, Ext JS, LLC.
23971 * Originally Released Under LGPL - original licence link has changed is not relivant.
23974 * <script type="text/javascript">
23978 * @class Roo.JsonView
23979 * @extends Roo.View
23980 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23982 var view = new Roo.JsonView({
23983 container: "my-element",
23984 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
23989 // listen for node click?
23990 view.on("click", function(vw, index, node, e){
23991 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23994 // direct load of JSON data
23995 view.load("foobar.php");
23997 // Example from my blog list
23998 var tpl = new Roo.Template(
23999 '<div class="entry">' +
24000 '<a class="entry-title" href="{link}">{title}</a>' +
24001 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24002 "</div><hr />"
24005 var moreView = new Roo.JsonView({
24006 container : "entry-list",
24010 moreView.on("beforerender", this.sortEntries, this);
24012 url: "/blog/get-posts.php",
24013 params: "allposts=true",
24014 text: "Loading Blog Entries..."
24018 * Note: old code is supported with arguments : (container, template, config)
24022 * Create a new JsonView
24024 * @param {Object} config The config object
24027 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24030 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24032 var um = this.el.getUpdateManager();
24033 um.setRenderer(this);
24034 um.on("update", this.onLoad, this);
24035 um.on("failure", this.onLoadException, this);
24038 * @event beforerender
24039 * Fires before rendering of the downloaded JSON data.
24040 * @param {Roo.JsonView} this
24041 * @param {Object} data The JSON data loaded
24045 * Fires when data is loaded.
24046 * @param {Roo.JsonView} this
24047 * @param {Object} data The JSON data loaded
24048 * @param {Object} response The raw Connect response object
24051 * @event loadexception
24052 * Fires when loading fails.
24053 * @param {Roo.JsonView} this
24054 * @param {Object} response The raw Connect response object
24057 'beforerender' : true,
24059 'loadexception' : true
24062 Roo.extend(Roo.JsonView, Roo.View, {
24064 * @type {String} The root property in the loaded JSON object that contains the data
24069 * Refreshes the view.
24071 refresh : function(){
24072 this.clearSelections();
24073 this.el.update("");
24075 var o = this.jsonData;
24076 if(o && o.length > 0){
24077 for(var i = 0, len = o.length; i < len; i++){
24078 var data = this.prepareData(o[i], i, o);
24079 html[html.length] = this.tpl.apply(data);
24082 html.push(this.emptyText);
24084 this.el.update(html.join(""));
24085 this.nodes = this.el.dom.childNodes;
24086 this.updateIndexes(0);
24090 * 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.
24091 * @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:
24094 url: "your-url.php",
24095 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24096 callback: yourFunction,
24097 scope: yourObject, //(optional scope)
24100 text: "Loading...",
24105 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24106 * 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.
24107 * @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}
24108 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24109 * @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.
24112 var um = this.el.getUpdateManager();
24113 um.update.apply(um, arguments);
24116 render : function(el, response){
24117 this.clearSelections();
24118 this.el.update("");
24121 o = Roo.util.JSON.decode(response.responseText);
24124 o = o[this.jsonRoot];
24129 * The current JSON data or null
24132 this.beforeRender();
24137 * Get the number of records in the current JSON dataset
24140 getCount : function(){
24141 return this.jsonData ? this.jsonData.length : 0;
24145 * Returns the JSON object for the specified node(s)
24146 * @param {HTMLElement/Array} node The node or an array of nodes
24147 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24148 * you get the JSON object for the node
24150 getNodeData : function(node){
24151 if(node instanceof Array){
24153 for(var i = 0, len = node.length; i < len; i++){
24154 data.push(this.getNodeData(node[i]));
24158 return this.jsonData[this.indexOf(node)] || null;
24161 beforeRender : function(){
24162 this.snapshot = this.jsonData;
24164 this.sort.apply(this, this.sortInfo);
24166 this.fireEvent("beforerender", this, this.jsonData);
24169 onLoad : function(el, o){
24170 this.fireEvent("load", this, this.jsonData, o);
24173 onLoadException : function(el, o){
24174 this.fireEvent("loadexception", this, o);
24178 * Filter the data by a specific property.
24179 * @param {String} property A property on your JSON objects
24180 * @param {String/RegExp} value Either string that the property values
24181 * should start with, or a RegExp to test against the property
24183 filter : function(property, value){
24186 var ss = this.snapshot;
24187 if(typeof value == "string"){
24188 var vlen = value.length;
24190 this.clearFilter();
24193 value = value.toLowerCase();
24194 for(var i = 0, len = ss.length; i < len; i++){
24196 if(o[property].substr(0, vlen).toLowerCase() == value){
24200 } else if(value.exec){ // regex?
24201 for(var i = 0, len = ss.length; i < len; i++){
24203 if(value.test(o[property])){
24210 this.jsonData = data;
24216 * Filter by a function. The passed function will be called with each
24217 * object in the current dataset. If the function returns true the value is kept,
24218 * otherwise it is filtered.
24219 * @param {Function} fn
24220 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24222 filterBy : function(fn, scope){
24225 var ss = this.snapshot;
24226 for(var i = 0, len = ss.length; i < len; i++){
24228 if(fn.call(scope || this, o)){
24232 this.jsonData = data;
24238 * Clears the current filter.
24240 clearFilter : function(){
24241 if(this.snapshot && this.jsonData != this.snapshot){
24242 this.jsonData = this.snapshot;
24249 * Sorts the data for this view and refreshes it.
24250 * @param {String} property A property on your JSON objects to sort on
24251 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24252 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24254 sort : function(property, dir, sortType){
24255 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24258 var dsc = dir && dir.toLowerCase() == "desc";
24259 var f = function(o1, o2){
24260 var v1 = sortType ? sortType(o1[p]) : o1[p];
24261 var v2 = sortType ? sortType(o2[p]) : o2[p];
24264 return dsc ? +1 : -1;
24265 } else if(v1 > v2){
24266 return dsc ? -1 : +1;
24271 this.jsonData.sort(f);
24273 if(this.jsonData != this.snapshot){
24274 this.snapshot.sort(f);
24280 * Ext JS Library 1.1.1
24281 * Copyright(c) 2006-2007, Ext JS, LLC.
24283 * Originally Released Under LGPL - original licence link has changed is not relivant.
24286 * <script type="text/javascript">
24291 * @class Roo.ColorPalette
24292 * @extends Roo.Component
24293 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24294 * Here's an example of typical usage:
24296 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24297 cp.render('my-div');
24299 cp.on('select', function(palette, selColor){
24300 // do something with selColor
24304 * Create a new ColorPalette
24305 * @param {Object} config The config object
24307 Roo.ColorPalette = function(config){
24308 Roo.ColorPalette.superclass.constructor.call(this, config);
24312 * Fires when a color is selected
24313 * @param {ColorPalette} this
24314 * @param {String} color The 6-digit color hex code (without the # symbol)
24320 this.on("select", this.handler, this.scope, true);
24323 Roo.extend(Roo.ColorPalette, Roo.Component, {
24325 * @cfg {String} itemCls
24326 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24328 itemCls : "x-color-palette",
24330 * @cfg {String} value
24331 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24332 * the hex codes are case-sensitive.
24335 clickEvent:'click',
24337 ctype: "Roo.ColorPalette",
24340 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24342 allowReselect : false,
24345 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24346 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24347 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24348 * of colors with the width setting until the box is symmetrical.</p>
24349 * <p>You can override individual colors if needed:</p>
24351 var cp = new Roo.ColorPalette();
24352 cp.colors[0] = "FF0000"; // change the first box to red
24355 Or you can provide a custom array of your own for complete control:
24357 var cp = new Roo.ColorPalette();
24358 cp.colors = ["000000", "993300", "333300"];
24363 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24364 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24365 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24366 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24367 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24371 onRender : function(container, position){
24372 var t = new Roo.MasterTemplate(
24373 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24375 var c = this.colors;
24376 for(var i = 0, len = c.length; i < len; i++){
24379 var el = document.createElement("div");
24380 el.className = this.itemCls;
24382 container.dom.insertBefore(el, position);
24383 this.el = Roo.get(el);
24384 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24385 if(this.clickEvent != 'click'){
24386 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24391 afterRender : function(){
24392 Roo.ColorPalette.superclass.afterRender.call(this);
24394 var s = this.value;
24401 handleClick : function(e, t){
24402 e.preventDefault();
24403 if(!this.disabled){
24404 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24405 this.select(c.toUpperCase());
24410 * Selects the specified color in the palette (fires the select event)
24411 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24413 select : function(color){
24414 color = color.replace("#", "");
24415 if(color != this.value || this.allowReselect){
24418 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24420 el.child("a.color-"+color).addClass("x-color-palette-sel");
24421 this.value = color;
24422 this.fireEvent("select", this, color);
24427 * Ext JS Library 1.1.1
24428 * Copyright(c) 2006-2007, Ext JS, LLC.
24430 * Originally Released Under LGPL - original licence link has changed is not relivant.
24433 * <script type="text/javascript">
24437 * @class Roo.DatePicker
24438 * @extends Roo.Component
24439 * Simple date picker class.
24441 * Create a new DatePicker
24442 * @param {Object} config The config object
24444 Roo.DatePicker = function(config){
24445 Roo.DatePicker.superclass.constructor.call(this, config);
24447 this.value = config && config.value ?
24448 config.value.clearTime() : new Date().clearTime();
24453 * Fires when a date is selected
24454 * @param {DatePicker} this
24455 * @param {Date} date The selected date
24461 this.on("select", this.handler, this.scope || this);
24463 // build the disabledDatesRE
24464 if(!this.disabledDatesRE && this.disabledDates){
24465 var dd = this.disabledDates;
24467 for(var i = 0; i < dd.length; i++){
24469 if(i != dd.length-1) re += "|";
24471 this.disabledDatesRE = new RegExp(re + ")");
24475 Roo.extend(Roo.DatePicker, Roo.Component, {
24477 * @cfg {String} todayText
24478 * The text to display on the button that selects the current date (defaults to "Today")
24480 todayText : "Today",
24482 * @cfg {String} okText
24483 * The text to display on the ok button
24485 okText : " OK ", //   to give the user extra clicking room
24487 * @cfg {String} cancelText
24488 * The text to display on the cancel button
24490 cancelText : "Cancel",
24492 * @cfg {String} todayTip
24493 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24495 todayTip : "{0} (Spacebar)",
24497 * @cfg {Date} minDate
24498 * Minimum allowable date (JavaScript date object, defaults to null)
24502 * @cfg {Date} maxDate
24503 * Maximum allowable date (JavaScript date object, defaults to null)
24507 * @cfg {String} minText
24508 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24510 minText : "This date is before the minimum date",
24512 * @cfg {String} maxText
24513 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24515 maxText : "This date is after the maximum date",
24517 * @cfg {String} format
24518 * The default date format string which can be overriden for localization support. The format must be
24519 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24523 * @cfg {Array} disabledDays
24524 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24526 disabledDays : null,
24528 * @cfg {String} disabledDaysText
24529 * The tooltip to display when the date falls on a disabled day (defaults to "")
24531 disabledDaysText : "",
24533 * @cfg {RegExp} disabledDatesRE
24534 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24536 disabledDatesRE : null,
24538 * @cfg {String} disabledDatesText
24539 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24541 disabledDatesText : "",
24543 * @cfg {Boolean} constrainToViewport
24544 * True to constrain the date picker to the viewport (defaults to true)
24546 constrainToViewport : true,
24548 * @cfg {Array} monthNames
24549 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24551 monthNames : Date.monthNames,
24553 * @cfg {Array} dayNames
24554 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24556 dayNames : Date.dayNames,
24558 * @cfg {String} nextText
24559 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24561 nextText: 'Next Month (Control+Right)',
24563 * @cfg {String} prevText
24564 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24566 prevText: 'Previous Month (Control+Left)',
24568 * @cfg {String} monthYearText
24569 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24571 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24573 * @cfg {Number} startDay
24574 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24578 * @cfg {Bool} showClear
24579 * Show a clear button (usefull for date form elements that can be blank.)
24585 * Sets the value of the date field
24586 * @param {Date} value The date to set
24588 setValue : function(value){
24589 var old = this.value;
24590 this.value = value.clearTime(true);
24592 this.update(this.value);
24597 * Gets the current selected value of the date field
24598 * @return {Date} The selected date
24600 getValue : function(){
24605 focus : function(){
24607 this.update(this.activeDate);
24612 onRender : function(container, position){
24614 '<table cellspacing="0">',
24615 '<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>',
24616 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24617 var dn = this.dayNames;
24618 for(var i = 0; i < 7; i++){
24619 var d = this.startDay+i;
24623 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24625 m[m.length] = "</tr></thead><tbody><tr>";
24626 for(var i = 0; i < 42; i++) {
24627 if(i % 7 == 0 && i != 0){
24628 m[m.length] = "</tr><tr>";
24630 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24632 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24633 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24635 var el = document.createElement("div");
24636 el.className = "x-date-picker";
24637 el.innerHTML = m.join("");
24639 container.dom.insertBefore(el, position);
24641 this.el = Roo.get(el);
24642 this.eventEl = Roo.get(el.firstChild);
24644 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24645 handler: this.showPrevMonth,
24647 preventDefault:true,
24651 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24652 handler: this.showNextMonth,
24654 preventDefault:true,
24658 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24660 this.monthPicker = this.el.down('div.x-date-mp');
24661 this.monthPicker.enableDisplayMode('block');
24663 var kn = new Roo.KeyNav(this.eventEl, {
24664 "left" : function(e){
24666 this.showPrevMonth() :
24667 this.update(this.activeDate.add("d", -1));
24670 "right" : function(e){
24672 this.showNextMonth() :
24673 this.update(this.activeDate.add("d", 1));
24676 "up" : function(e){
24678 this.showNextYear() :
24679 this.update(this.activeDate.add("d", -7));
24682 "down" : function(e){
24684 this.showPrevYear() :
24685 this.update(this.activeDate.add("d", 7));
24688 "pageUp" : function(e){
24689 this.showNextMonth();
24692 "pageDown" : function(e){
24693 this.showPrevMonth();
24696 "enter" : function(e){
24697 e.stopPropagation();
24704 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24706 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24708 this.el.unselectable();
24710 this.cells = this.el.select("table.x-date-inner tbody td");
24711 this.textNodes = this.el.query("table.x-date-inner tbody span");
24713 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24715 tooltip: this.monthYearText
24718 this.mbtn.on('click', this.showMonthPicker, this);
24719 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24722 var today = (new Date()).dateFormat(this.format);
24724 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24725 if (this.showClear) {
24726 baseTb.add( new Roo.Toolbar.Fill());
24729 text: String.format(this.todayText, today),
24730 tooltip: String.format(this.todayTip, today),
24731 handler: this.selectToday,
24735 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24738 if (this.showClear) {
24740 baseTb.add( new Roo.Toolbar.Fill());
24743 cls: 'x-btn-icon x-btn-clear',
24744 handler: function() {
24746 this.fireEvent("select", this, '');
24756 this.update(this.value);
24759 createMonthPicker : function(){
24760 if(!this.monthPicker.dom.firstChild){
24761 var buf = ['<table border="0" cellspacing="0">'];
24762 for(var i = 0; i < 6; i++){
24764 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24765 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24767 '<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>' :
24768 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24772 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24774 '</button><button type="button" class="x-date-mp-cancel">',
24776 '</button></td></tr>',
24779 this.monthPicker.update(buf.join(''));
24780 this.monthPicker.on('click', this.onMonthClick, this);
24781 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24783 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24784 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24786 this.mpMonths.each(function(m, a, i){
24789 m.dom.xmonth = 5 + Math.round(i * .5);
24791 m.dom.xmonth = Math.round((i-1) * .5);
24797 showMonthPicker : function(){
24798 this.createMonthPicker();
24799 var size = this.el.getSize();
24800 this.monthPicker.setSize(size);
24801 this.monthPicker.child('table').setSize(size);
24803 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24804 this.updateMPMonth(this.mpSelMonth);
24805 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24806 this.updateMPYear(this.mpSelYear);
24808 this.monthPicker.slideIn('t', {duration:.2});
24811 updateMPYear : function(y){
24813 var ys = this.mpYears.elements;
24814 for(var i = 1; i <= 10; i++){
24815 var td = ys[i-1], y2;
24817 y2 = y + Math.round(i * .5);
24818 td.firstChild.innerHTML = y2;
24821 y2 = y - (5-Math.round(i * .5));
24822 td.firstChild.innerHTML = y2;
24825 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24829 updateMPMonth : function(sm){
24830 this.mpMonths.each(function(m, a, i){
24831 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24835 selectMPMonth: function(m){
24839 onMonthClick : function(e, t){
24841 var el = new Roo.Element(t), pn;
24842 if(el.is('button.x-date-mp-cancel')){
24843 this.hideMonthPicker();
24845 else if(el.is('button.x-date-mp-ok')){
24846 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24847 this.hideMonthPicker();
24849 else if(pn = el.up('td.x-date-mp-month', 2)){
24850 this.mpMonths.removeClass('x-date-mp-sel');
24851 pn.addClass('x-date-mp-sel');
24852 this.mpSelMonth = pn.dom.xmonth;
24854 else if(pn = el.up('td.x-date-mp-year', 2)){
24855 this.mpYears.removeClass('x-date-mp-sel');
24856 pn.addClass('x-date-mp-sel');
24857 this.mpSelYear = pn.dom.xyear;
24859 else if(el.is('a.x-date-mp-prev')){
24860 this.updateMPYear(this.mpyear-10);
24862 else if(el.is('a.x-date-mp-next')){
24863 this.updateMPYear(this.mpyear+10);
24867 onMonthDblClick : function(e, t){
24869 var el = new Roo.Element(t), pn;
24870 if(pn = el.up('td.x-date-mp-month', 2)){
24871 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24872 this.hideMonthPicker();
24874 else if(pn = el.up('td.x-date-mp-year', 2)){
24875 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24876 this.hideMonthPicker();
24880 hideMonthPicker : function(disableAnim){
24881 if(this.monthPicker){
24882 if(disableAnim === true){
24883 this.monthPicker.hide();
24885 this.monthPicker.slideOut('t', {duration:.2});
24891 showPrevMonth : function(e){
24892 this.update(this.activeDate.add("mo", -1));
24896 showNextMonth : function(e){
24897 this.update(this.activeDate.add("mo", 1));
24901 showPrevYear : function(){
24902 this.update(this.activeDate.add("y", -1));
24906 showNextYear : function(){
24907 this.update(this.activeDate.add("y", 1));
24911 handleMouseWheel : function(e){
24912 var delta = e.getWheelDelta();
24914 this.showPrevMonth();
24916 } else if(delta < 0){
24917 this.showNextMonth();
24923 handleDateClick : function(e, t){
24925 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24926 this.setValue(new Date(t.dateValue));
24927 this.fireEvent("select", this, this.value);
24932 selectToday : function(){
24933 this.setValue(new Date().clearTime());
24934 this.fireEvent("select", this, this.value);
24938 update : function(date){
24939 var vd = this.activeDate;
24940 this.activeDate = date;
24942 var t = date.getTime();
24943 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24944 this.cells.removeClass("x-date-selected");
24945 this.cells.each(function(c){
24946 if(c.dom.firstChild.dateValue == t){
24947 c.addClass("x-date-selected");
24948 setTimeout(function(){
24949 try{c.dom.firstChild.focus();}catch(e){}
24957 var days = date.getDaysInMonth();
24958 var firstOfMonth = date.getFirstDateOfMonth();
24959 var startingPos = firstOfMonth.getDay()-this.startDay;
24961 if(startingPos <= this.startDay){
24965 var pm = date.add("mo", -1);
24966 var prevStart = pm.getDaysInMonth()-startingPos;
24968 var cells = this.cells.elements;
24969 var textEls = this.textNodes;
24970 days += startingPos;
24972 // convert everything to numbers so it's fast
24973 var day = 86400000;
24974 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24975 var today = new Date().clearTime().getTime();
24976 var sel = date.clearTime().getTime();
24977 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24978 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24979 var ddMatch = this.disabledDatesRE;
24980 var ddText = this.disabledDatesText;
24981 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24982 var ddaysText = this.disabledDaysText;
24983 var format = this.format;
24985 var setCellClass = function(cal, cell){
24987 var t = d.getTime();
24988 cell.firstChild.dateValue = t;
24990 cell.className += " x-date-today";
24991 cell.title = cal.todayText;
24994 cell.className += " x-date-selected";
24995 setTimeout(function(){
24996 try{cell.firstChild.focus();}catch(e){}
25001 cell.className = " x-date-disabled";
25002 cell.title = cal.minText;
25006 cell.className = " x-date-disabled";
25007 cell.title = cal.maxText;
25011 if(ddays.indexOf(d.getDay()) != -1){
25012 cell.title = ddaysText;
25013 cell.className = " x-date-disabled";
25016 if(ddMatch && format){
25017 var fvalue = d.dateFormat(format);
25018 if(ddMatch.test(fvalue)){
25019 cell.title = ddText.replace("%0", fvalue);
25020 cell.className = " x-date-disabled";
25026 for(; i < startingPos; i++) {
25027 textEls[i].innerHTML = (++prevStart);
25028 d.setDate(d.getDate()+1);
25029 cells[i].className = "x-date-prevday";
25030 setCellClass(this, cells[i]);
25032 for(; i < days; i++){
25033 intDay = i - startingPos + 1;
25034 textEls[i].innerHTML = (intDay);
25035 d.setDate(d.getDate()+1);
25036 cells[i].className = "x-date-active";
25037 setCellClass(this, cells[i]);
25040 for(; i < 42; i++) {
25041 textEls[i].innerHTML = (++extraDays);
25042 d.setDate(d.getDate()+1);
25043 cells[i].className = "x-date-nextday";
25044 setCellClass(this, cells[i]);
25047 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25049 if(!this.internalRender){
25050 var main = this.el.dom.firstChild;
25051 var w = main.offsetWidth;
25052 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25053 Roo.fly(main).setWidth(w);
25054 this.internalRender = true;
25055 // opera does not respect the auto grow header center column
25056 // then, after it gets a width opera refuses to recalculate
25057 // without a second pass
25058 if(Roo.isOpera && !this.secondPass){
25059 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25060 this.secondPass = true;
25061 this.update.defer(10, this, [date]);
25067 * Ext JS Library 1.1.1
25068 * Copyright(c) 2006-2007, Ext JS, LLC.
25070 * Originally Released Under LGPL - original licence link has changed is not relivant.
25073 * <script type="text/javascript">
25076 * @class Roo.TabPanel
25077 * @extends Roo.util.Observable
25078 * A lightweight tab container.
25082 // basic tabs 1, built from existing content
25083 var tabs = new Roo.TabPanel("tabs1");
25084 tabs.addTab("script", "View Script");
25085 tabs.addTab("markup", "View Markup");
25086 tabs.activate("script");
25088 // more advanced tabs, built from javascript
25089 var jtabs = new Roo.TabPanel("jtabs");
25090 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25092 // set up the UpdateManager
25093 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25094 var updater = tab2.getUpdateManager();
25095 updater.setDefaultUrl("ajax1.htm");
25096 tab2.on('activate', updater.refresh, updater, true);
25098 // Use setUrl for Ajax loading
25099 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25100 tab3.setUrl("ajax2.htm", null, true);
25103 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25106 jtabs.activate("jtabs-1");
25109 * Create a new TabPanel.
25110 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25111 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25113 Roo.TabPanel = function(container, config){
25115 * The container element for this TabPanel.
25116 * @type Roo.Element
25118 this.el = Roo.get(container, true);
25120 if(typeof config == "boolean"){
25121 this.tabPosition = config ? "bottom" : "top";
25123 Roo.apply(this, config);
25126 if(this.tabPosition == "bottom"){
25127 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25128 this.el.addClass("x-tabs-bottom");
25130 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25131 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25132 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25134 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25136 if(this.tabPosition != "bottom"){
25137 /** The body element that contains {@link Roo.TabPanelItem} bodies.
25138 * @type Roo.Element
25140 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25141 this.el.addClass("x-tabs-top");
25145 this.bodyEl.setStyle("position", "relative");
25147 this.active = null;
25148 this.activateDelegate = this.activate.createDelegate(this);
25153 * Fires when the active tab changes
25154 * @param {Roo.TabPanel} this
25155 * @param {Roo.TabPanelItem} activePanel The new active tab
25159 * @event beforetabchange
25160 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25161 * @param {Roo.TabPanel} this
25162 * @param {Object} e Set cancel to true on this object to cancel the tab change
25163 * @param {Roo.TabPanelItem} tab The tab being changed to
25165 "beforetabchange" : true
25168 Roo.EventManager.onWindowResize(this.onResize, this);
25169 this.cpad = this.el.getPadding("lr");
25170 this.hiddenCount = 0;
25172 Roo.TabPanel.superclass.constructor.call(this);
25175 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25177 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25179 tabPosition : "top",
25181 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25183 currentTabWidth : 0,
25185 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25189 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25193 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25195 preferredTabWidth : 175,
25197 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25199 resizeTabs : false,
25201 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25203 monitorResize : true,
25206 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25207 * @param {String} id The id of the div to use <b>or create</b>
25208 * @param {String} text The text for the tab
25209 * @param {String} content (optional) Content to put in the TabPanelItem body
25210 * @param {Boolean} closable (optional) True to create a close icon on the tab
25211 * @return {Roo.TabPanelItem} The created TabPanelItem
25213 addTab : function(id, text, content, closable){
25214 var item = new Roo.TabPanelItem(this, id, text, closable);
25215 this.addTabItem(item);
25217 item.setContent(content);
25223 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25224 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25225 * @return {Roo.TabPanelItem}
25227 getTab : function(id){
25228 return this.items[id];
25232 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25233 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25235 hideTab : function(id){
25236 var t = this.items[id];
25239 this.hiddenCount++;
25240 this.autoSizeTabs();
25245 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25246 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25248 unhideTab : function(id){
25249 var t = this.items[id];
25251 t.setHidden(false);
25252 this.hiddenCount--;
25253 this.autoSizeTabs();
25258 * Adds an existing {@link Roo.TabPanelItem}.
25259 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25261 addTabItem : function(item){
25262 this.items[item.id] = item;
25263 this.items.push(item);
25264 if(this.resizeTabs){
25265 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25266 this.autoSizeTabs();
25273 * Removes a {@link Roo.TabPanelItem}.
25274 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25276 removeTab : function(id){
25277 var items = this.items;
25278 var tab = items[id];
25279 if(!tab) { return; }
25280 var index = items.indexOf(tab);
25281 if(this.active == tab && items.length > 1){
25282 var newTab = this.getNextAvailable(index);
25287 this.stripEl.dom.removeChild(tab.pnode.dom);
25288 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25289 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25291 items.splice(index, 1);
25292 delete this.items[tab.id];
25293 tab.fireEvent("close", tab);
25294 tab.purgeListeners();
25295 this.autoSizeTabs();
25298 getNextAvailable : function(start){
25299 var items = this.items;
25301 // look for a next tab that will slide over to
25302 // replace the one being removed
25303 while(index < items.length){
25304 var item = items[++index];
25305 if(item && !item.isHidden()){
25309 // if one isn't found select the previous tab (on the left)
25312 var item = items[--index];
25313 if(item && !item.isHidden()){
25321 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25322 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25324 disableTab : function(id){
25325 var tab = this.items[id];
25326 if(tab && this.active != tab){
25332 * Enables a {@link Roo.TabPanelItem} that is disabled.
25333 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25335 enableTab : function(id){
25336 var tab = this.items[id];
25341 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25342 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25343 * @return {Roo.TabPanelItem} The TabPanelItem.
25345 activate : function(id){
25346 var tab = this.items[id];
25350 if(tab == this.active || tab.disabled){
25354 this.fireEvent("beforetabchange", this, e, tab);
25355 if(e.cancel !== true && !tab.disabled){
25357 this.active.hide();
25359 this.active = this.items[id];
25360 this.active.show();
25361 this.fireEvent("tabchange", this, this.active);
25367 * Gets the active {@link Roo.TabPanelItem}.
25368 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25370 getActiveTab : function(){
25371 return this.active;
25375 * Updates the tab body element to fit the height of the container element
25376 * for overflow scrolling
25377 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25379 syncHeight : function(targetHeight){
25380 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25381 var bm = this.bodyEl.getMargins();
25382 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25383 this.bodyEl.setHeight(newHeight);
25387 onResize : function(){
25388 if(this.monitorResize){
25389 this.autoSizeTabs();
25394 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25396 beginUpdate : function(){
25397 this.updating = true;
25401 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25403 endUpdate : function(){
25404 this.updating = false;
25405 this.autoSizeTabs();
25409 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25411 autoSizeTabs : function(){
25412 var count = this.items.length;
25413 var vcount = count - this.hiddenCount;
25414 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25415 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25416 var availWidth = Math.floor(w / vcount);
25417 var b = this.stripBody;
25418 if(b.getWidth() > w){
25419 var tabs = this.items;
25420 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25421 if(availWidth < this.minTabWidth){
25422 /*if(!this.sleft){ // incomplete scrolling code
25423 this.createScrollButtons();
25426 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25429 if(this.currentTabWidth < this.preferredTabWidth){
25430 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25436 * Returns the number of tabs in this TabPanel.
25439 getCount : function(){
25440 return this.items.length;
25444 * Resizes all the tabs to the passed width
25445 * @param {Number} The new width
25447 setTabWidth : function(width){
25448 this.currentTabWidth = width;
25449 for(var i = 0, len = this.items.length; i < len; i++) {
25450 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25455 * Destroys this TabPanel
25456 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25458 destroy : function(removeEl){
25459 Roo.EventManager.removeResizeListener(this.onResize, this);
25460 for(var i = 0, len = this.items.length; i < len; i++){
25461 this.items[i].purgeListeners();
25463 if(removeEl === true){
25464 this.el.update("");
25471 * @class Roo.TabPanelItem
25472 * @extends Roo.util.Observable
25473 * Represents an individual item (tab plus body) in a TabPanel.
25474 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25475 * @param {String} id The id of this TabPanelItem
25476 * @param {String} text The text for the tab of this TabPanelItem
25477 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25479 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25481 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25482 * @type Roo.TabPanel
25484 this.tabPanel = tabPanel;
25486 * The id for this TabPanelItem
25491 this.disabled = false;
25495 this.loaded = false;
25496 this.closable = closable;
25499 * The body element for this TabPanelItem.
25500 * @type Roo.Element
25502 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25503 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25504 this.bodyEl.setStyle("display", "block");
25505 this.bodyEl.setStyle("zoom", "1");
25508 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25510 this.el = Roo.get(els.el, true);
25511 this.inner = Roo.get(els.inner, true);
25512 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25513 this.pnode = Roo.get(els.el.parentNode, true);
25514 this.el.on("mousedown", this.onTabMouseDown, this);
25515 this.el.on("click", this.onTabClick, this);
25518 var c = Roo.get(els.close, true);
25519 c.dom.title = this.closeText;
25520 c.addClassOnOver("close-over");
25521 c.on("click", this.closeClick, this);
25527 * Fires when this tab becomes the active tab.
25528 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25529 * @param {Roo.TabPanelItem} this
25533 * @event beforeclose
25534 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25535 * @param {Roo.TabPanelItem} this
25536 * @param {Object} e Set cancel to true on this object to cancel the close.
25538 "beforeclose": true,
25541 * Fires when this tab is closed.
25542 * @param {Roo.TabPanelItem} this
25546 * @event deactivate
25547 * Fires when this tab is no longer the active tab.
25548 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25549 * @param {Roo.TabPanelItem} this
25551 "deactivate" : true
25553 this.hidden = false;
25555 Roo.TabPanelItem.superclass.constructor.call(this);
25558 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25559 purgeListeners : function(){
25560 Roo.util.Observable.prototype.purgeListeners.call(this);
25561 this.el.removeAllListeners();
25564 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25567 this.pnode.addClass("on");
25570 this.tabPanel.stripWrap.repaint();
25572 this.fireEvent("activate", this.tabPanel, this);
25576 * Returns true if this tab is the active tab.
25577 * @return {Boolean}
25579 isActive : function(){
25580 return this.tabPanel.getActiveTab() == this;
25584 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25587 this.pnode.removeClass("on");
25589 this.fireEvent("deactivate", this.tabPanel, this);
25592 hideAction : function(){
25593 this.bodyEl.hide();
25594 this.bodyEl.setStyle("position", "absolute");
25595 this.bodyEl.setLeft("-20000px");
25596 this.bodyEl.setTop("-20000px");
25599 showAction : function(){
25600 this.bodyEl.setStyle("position", "relative");
25601 this.bodyEl.setTop("");
25602 this.bodyEl.setLeft("");
25603 this.bodyEl.show();
25607 * Set the tooltip for the tab.
25608 * @param {String} tooltip The tab's tooltip
25610 setTooltip : function(text){
25611 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25612 this.textEl.dom.qtip = text;
25613 this.textEl.dom.removeAttribute('title');
25615 this.textEl.dom.title = text;
25619 onTabClick : function(e){
25620 e.preventDefault();
25621 this.tabPanel.activate(this.id);
25624 onTabMouseDown : function(e){
25625 e.preventDefault();
25626 this.tabPanel.activate(this.id);
25629 getWidth : function(){
25630 return this.inner.getWidth();
25633 setWidth : function(width){
25634 var iwidth = width - this.pnode.getPadding("lr");
25635 this.inner.setWidth(iwidth);
25636 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25637 this.pnode.setWidth(width);
25641 * Show or hide the tab
25642 * @param {Boolean} hidden True to hide or false to show.
25644 setHidden : function(hidden){
25645 this.hidden = hidden;
25646 this.pnode.setStyle("display", hidden ? "none" : "");
25650 * Returns true if this tab is "hidden"
25651 * @return {Boolean}
25653 isHidden : function(){
25654 return this.hidden;
25658 * Returns the text for this tab
25661 getText : function(){
25665 autoSize : function(){
25666 //this.el.beginMeasure();
25667 this.textEl.setWidth(1);
25668 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25669 //this.el.endMeasure();
25673 * Sets the text for the tab (Note: this also sets the tooltip text)
25674 * @param {String} text The tab's text and tooltip
25676 setText : function(text){
25678 this.textEl.update(text);
25679 this.setTooltip(text);
25680 if(!this.tabPanel.resizeTabs){
25685 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25687 activate : function(){
25688 this.tabPanel.activate(this.id);
25692 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25694 disable : function(){
25695 if(this.tabPanel.active != this){
25696 this.disabled = true;
25697 this.pnode.addClass("disabled");
25702 * Enables this TabPanelItem if it was previously disabled.
25704 enable : function(){
25705 this.disabled = false;
25706 this.pnode.removeClass("disabled");
25710 * Sets the content for this TabPanelItem.
25711 * @param {String} content The content
25712 * @param {Boolean} loadScripts true to look for and load scripts
25714 setContent : function(content, loadScripts){
25715 this.bodyEl.update(content, loadScripts);
25719 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25720 * @return {Roo.UpdateManager} The UpdateManager
25722 getUpdateManager : function(){
25723 return this.bodyEl.getUpdateManager();
25727 * Set a URL to be used to load the content for this TabPanelItem.
25728 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25729 * @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)
25730 * @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)
25731 * @return {Roo.UpdateManager} The UpdateManager
25733 setUrl : function(url, params, loadOnce){
25734 if(this.refreshDelegate){
25735 this.un('activate', this.refreshDelegate);
25737 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25738 this.on("activate", this.refreshDelegate);
25739 return this.bodyEl.getUpdateManager();
25743 _handleRefresh : function(url, params, loadOnce){
25744 if(!loadOnce || !this.loaded){
25745 var updater = this.bodyEl.getUpdateManager();
25746 updater.update(url, params, this._setLoaded.createDelegate(this));
25751 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25752 * Will fail silently if the setUrl method has not been called.
25753 * This does not activate the panel, just updates its content.
25755 refresh : function(){
25756 if(this.refreshDelegate){
25757 this.loaded = false;
25758 this.refreshDelegate();
25763 _setLoaded : function(){
25764 this.loaded = true;
25768 closeClick : function(e){
25771 this.fireEvent("beforeclose", this, o);
25772 if(o.cancel !== true){
25773 this.tabPanel.removeTab(this.id);
25777 * The text displayed in the tooltip for the close icon.
25780 closeText : "Close this tab"
25784 Roo.TabPanel.prototype.createStrip = function(container){
25785 var strip = document.createElement("div");
25786 strip.className = "x-tabs-wrap";
25787 container.appendChild(strip);
25791 Roo.TabPanel.prototype.createStripList = function(strip){
25792 // div wrapper for retard IE
25793 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>';
25794 return strip.firstChild.firstChild.firstChild.firstChild;
25797 Roo.TabPanel.prototype.createBody = function(container){
25798 var body = document.createElement("div");
25799 Roo.id(body, "tab-body");
25800 Roo.fly(body).addClass("x-tabs-body");
25801 container.appendChild(body);
25805 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25806 var body = Roo.getDom(id);
25808 body = document.createElement("div");
25811 Roo.fly(body).addClass("x-tabs-item-body");
25812 bodyEl.insertBefore(body, bodyEl.firstChild);
25816 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25817 var td = document.createElement("td");
25818 stripEl.appendChild(td);
25820 td.className = "x-tabs-closable";
25821 if(!this.closeTpl){
25822 this.closeTpl = new Roo.Template(
25823 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25824 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25825 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25828 var el = this.closeTpl.overwrite(td, {"text": text});
25829 var close = el.getElementsByTagName("div")[0];
25830 var inner = el.getElementsByTagName("em")[0];
25831 return {"el": el, "close": close, "inner": inner};
25834 this.tabTpl = new Roo.Template(
25835 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25836 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25839 var el = this.tabTpl.overwrite(td, {"text": text});
25840 var inner = el.getElementsByTagName("em")[0];
25841 return {"el": el, "inner": inner};
25845 * Ext JS Library 1.1.1
25846 * Copyright(c) 2006-2007, Ext JS, LLC.
25848 * Originally Released Under LGPL - original licence link has changed is not relivant.
25851 * <script type="text/javascript">
25855 * @class Roo.Button
25856 * @extends Roo.util.Observable
25857 * Simple Button class
25858 * @cfg {String} text The button text
25859 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25860 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25861 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25862 * @cfg {Object} scope The scope of the handler
25863 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25864 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25865 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25866 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25867 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25868 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25869 applies if enableToggle = true)
25870 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25871 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25872 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25874 * Create a new button
25875 * @param {Object} config The config object
25877 Roo.Button = function(renderTo, config)
25881 renderTo = config.renderTo || false;
25884 Roo.apply(this, config);
25888 * Fires when this button is clicked
25889 * @param {Button} this
25890 * @param {EventObject} e The click event
25895 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25896 * @param {Button} this
25897 * @param {Boolean} pressed
25902 * Fires when the mouse hovers over the button
25903 * @param {Button} this
25904 * @param {Event} e The event object
25906 'mouseover' : true,
25909 * Fires when the mouse exits the button
25910 * @param {Button} this
25911 * @param {Event} e The event object
25916 * Fires when the button is rendered
25917 * @param {Button} this
25922 this.menu = Roo.menu.MenuMgr.get(this.menu);
25924 // register listeners first!! - so render can be captured..
25925 Roo.util.Observable.call(this);
25927 this.render(renderTo);
25933 Roo.extend(Roo.Button, Roo.util.Observable, {
25939 * Read-only. True if this button is hidden
25944 * Read-only. True if this button is disabled
25949 * Read-only. True if this button is pressed (only if enableToggle = true)
25955 * @cfg {Number} tabIndex
25956 * The DOM tabIndex for this button (defaults to undefined)
25958 tabIndex : undefined,
25961 * @cfg {Boolean} enableToggle
25962 * True to enable pressed/not pressed toggling (defaults to false)
25964 enableToggle: false,
25966 * @cfg {Mixed} menu
25967 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25971 * @cfg {String} menuAlign
25972 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25974 menuAlign : "tl-bl?",
25977 * @cfg {String} iconCls
25978 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25980 iconCls : undefined,
25982 * @cfg {String} type
25983 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25988 menuClassTarget: 'tr',
25991 * @cfg {String} clickEvent
25992 * The type of event to map to the button's event handler (defaults to 'click')
25994 clickEvent : 'click',
25997 * @cfg {Boolean} handleMouseEvents
25998 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26000 handleMouseEvents : true,
26003 * @cfg {String} tooltipType
26004 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26006 tooltipType : 'qtip',
26009 * @cfg {String} cls
26010 * A CSS class to apply to the button's main element.
26014 * @cfg {Roo.Template} template (Optional)
26015 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26016 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26017 * require code modifications if required elements (e.g. a button) aren't present.
26021 render : function(renderTo){
26023 if(this.hideParent){
26024 this.parentEl = Roo.get(renderTo);
26026 if(!this.dhconfig){
26027 if(!this.template){
26028 if(!Roo.Button.buttonTemplate){
26029 // hideous table template
26030 Roo.Button.buttonTemplate = new Roo.Template(
26031 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26032 '<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>',
26033 "</tr></tbody></table>");
26035 this.template = Roo.Button.buttonTemplate;
26037 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26038 var btnEl = btn.child("button:first");
26039 btnEl.on('focus', this.onFocus, this);
26040 btnEl.on('blur', this.onBlur, this);
26042 btn.addClass(this.cls);
26045 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26048 btnEl.addClass(this.iconCls);
26050 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26053 if(this.tabIndex !== undefined){
26054 btnEl.dom.tabIndex = this.tabIndex;
26057 if(typeof this.tooltip == 'object'){
26058 Roo.QuickTips.tips(Roo.apply({
26062 btnEl.dom[this.tooltipType] = this.tooltip;
26066 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26070 this.el.dom.id = this.el.id = this.id;
26073 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26074 this.menu.on("show", this.onMenuShow, this);
26075 this.menu.on("hide", this.onMenuHide, this);
26077 btn.addClass("x-btn");
26078 if(Roo.isIE && !Roo.isIE7){
26079 this.autoWidth.defer(1, this);
26083 if(this.handleMouseEvents){
26084 btn.on("mouseover", this.onMouseOver, this);
26085 btn.on("mouseout", this.onMouseOut, this);
26086 btn.on("mousedown", this.onMouseDown, this);
26088 btn.on(this.clickEvent, this.onClick, this);
26089 //btn.on("mouseup", this.onMouseUp, this);
26096 Roo.ButtonToggleMgr.register(this);
26098 this.el.addClass("x-btn-pressed");
26101 var repeater = new Roo.util.ClickRepeater(btn,
26102 typeof this.repeat == "object" ? this.repeat : {}
26104 repeater.on("click", this.onClick, this);
26107 this.fireEvent('render', this);
26111 * Returns the button's underlying element
26112 * @return {Roo.Element} The element
26114 getEl : function(){
26119 * Destroys this Button and removes any listeners.
26121 destroy : function(){
26122 Roo.ButtonToggleMgr.unregister(this);
26123 this.el.removeAllListeners();
26124 this.purgeListeners();
26129 autoWidth : function(){
26131 this.el.setWidth("auto");
26132 if(Roo.isIE7 && Roo.isStrict){
26133 var ib = this.el.child('button');
26134 if(ib && ib.getWidth() > 20){
26136 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26141 this.el.beginMeasure();
26143 if(this.el.getWidth() < this.minWidth){
26144 this.el.setWidth(this.minWidth);
26147 this.el.endMeasure();
26154 * Assigns this button's click handler
26155 * @param {Function} handler The function to call when the button is clicked
26156 * @param {Object} scope (optional) Scope for the function passed in
26158 setHandler : function(handler, scope){
26159 this.handler = handler;
26160 this.scope = scope;
26164 * Sets this button's text
26165 * @param {String} text The button text
26167 setText : function(text){
26170 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26176 * Gets the text for this button
26177 * @return {String} The button text
26179 getText : function(){
26187 this.hidden = false;
26189 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26197 this.hidden = true;
26199 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26204 * Convenience function for boolean show/hide
26205 * @param {Boolean} visible True to show, false to hide
26207 setVisible: function(visible){
26216 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26217 * @param {Boolean} state (optional) Force a particular state
26219 toggle : function(state){
26220 state = state === undefined ? !this.pressed : state;
26221 if(state != this.pressed){
26223 this.el.addClass("x-btn-pressed");
26224 this.pressed = true;
26225 this.fireEvent("toggle", this, true);
26227 this.el.removeClass("x-btn-pressed");
26228 this.pressed = false;
26229 this.fireEvent("toggle", this, false);
26231 if(this.toggleHandler){
26232 this.toggleHandler.call(this.scope || this, this, state);
26240 focus : function(){
26241 this.el.child('button:first').focus();
26245 * Disable this button
26247 disable : function(){
26249 this.el.addClass("x-btn-disabled");
26251 this.disabled = true;
26255 * Enable this button
26257 enable : function(){
26259 this.el.removeClass("x-btn-disabled");
26261 this.disabled = false;
26265 * Convenience function for boolean enable/disable
26266 * @param {Boolean} enabled True to enable, false to disable
26268 setDisabled : function(v){
26269 this[v !== true ? "enable" : "disable"]();
26273 onClick : function(e){
26275 e.preventDefault();
26280 if(!this.disabled){
26281 if(this.enableToggle){
26284 if(this.menu && !this.menu.isVisible()){
26285 this.menu.show(this.el, this.menuAlign);
26287 this.fireEvent("click", this, e);
26289 this.el.removeClass("x-btn-over");
26290 this.handler.call(this.scope || this, this, e);
26295 onMouseOver : function(e){
26296 if(!this.disabled){
26297 this.el.addClass("x-btn-over");
26298 this.fireEvent('mouseover', this, e);
26302 onMouseOut : function(e){
26303 if(!e.within(this.el, true)){
26304 this.el.removeClass("x-btn-over");
26305 this.fireEvent('mouseout', this, e);
26309 onFocus : function(e){
26310 if(!this.disabled){
26311 this.el.addClass("x-btn-focus");
26315 onBlur : function(e){
26316 this.el.removeClass("x-btn-focus");
26319 onMouseDown : function(e){
26320 if(!this.disabled && e.button == 0){
26321 this.el.addClass("x-btn-click");
26322 Roo.get(document).on('mouseup', this.onMouseUp, this);
26326 onMouseUp : function(e){
26328 this.el.removeClass("x-btn-click");
26329 Roo.get(document).un('mouseup', this.onMouseUp, this);
26333 onMenuShow : function(e){
26334 this.el.addClass("x-btn-menu-active");
26337 onMenuHide : function(e){
26338 this.el.removeClass("x-btn-menu-active");
26342 // Private utility class used by Button
26343 Roo.ButtonToggleMgr = function(){
26346 function toggleGroup(btn, state){
26348 var g = groups[btn.toggleGroup];
26349 for(var i = 0, l = g.length; i < l; i++){
26351 g[i].toggle(false);
26358 register : function(btn){
26359 if(!btn.toggleGroup){
26362 var g = groups[btn.toggleGroup];
26364 g = groups[btn.toggleGroup] = [];
26367 btn.on("toggle", toggleGroup);
26370 unregister : function(btn){
26371 if(!btn.toggleGroup){
26374 var g = groups[btn.toggleGroup];
26377 btn.un("toggle", toggleGroup);
26383 * Ext JS Library 1.1.1
26384 * Copyright(c) 2006-2007, Ext JS, LLC.
26386 * Originally Released Under LGPL - original licence link has changed is not relivant.
26389 * <script type="text/javascript">
26393 * @class Roo.SplitButton
26394 * @extends Roo.Button
26395 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26396 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26397 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26398 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26399 * @cfg {String} arrowTooltip The title attribute of the arrow
26401 * Create a new menu button
26402 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26403 * @param {Object} config The config object
26405 Roo.SplitButton = function(renderTo, config){
26406 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26408 * @event arrowclick
26409 * Fires when this button's arrow is clicked
26410 * @param {SplitButton} this
26411 * @param {EventObject} e The click event
26413 this.addEvents({"arrowclick":true});
26416 Roo.extend(Roo.SplitButton, Roo.Button, {
26417 render : function(renderTo){
26418 // this is one sweet looking template!
26419 var tpl = new Roo.Template(
26420 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26421 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26422 '<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>',
26423 "</tbody></table></td><td>",
26424 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26425 '<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>',
26426 "</tbody></table></td></tr></table>"
26428 var btn = tpl.append(renderTo, [this.text, this.type], true);
26429 var btnEl = btn.child("button");
26431 btn.addClass(this.cls);
26434 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26437 btnEl.addClass(this.iconCls);
26439 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26443 if(this.handleMouseEvents){
26444 btn.on("mouseover", this.onMouseOver, this);
26445 btn.on("mouseout", this.onMouseOut, this);
26446 btn.on("mousedown", this.onMouseDown, this);
26447 btn.on("mouseup", this.onMouseUp, this);
26449 btn.on(this.clickEvent, this.onClick, this);
26451 if(typeof this.tooltip == 'object'){
26452 Roo.QuickTips.tips(Roo.apply({
26456 btnEl.dom[this.tooltipType] = this.tooltip;
26459 if(this.arrowTooltip){
26460 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26469 this.el.addClass("x-btn-pressed");
26471 if(Roo.isIE && !Roo.isIE7){
26472 this.autoWidth.defer(1, this);
26477 this.menu.on("show", this.onMenuShow, this);
26478 this.menu.on("hide", this.onMenuHide, this);
26480 this.fireEvent('render', this);
26484 autoWidth : function(){
26486 var tbl = this.el.child("table:first");
26487 var tbl2 = this.el.child("table:last");
26488 this.el.setWidth("auto");
26489 tbl.setWidth("auto");
26490 if(Roo.isIE7 && Roo.isStrict){
26491 var ib = this.el.child('button:first');
26492 if(ib && ib.getWidth() > 20){
26494 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26499 this.el.beginMeasure();
26501 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26502 tbl.setWidth(this.minWidth-tbl2.getWidth());
26505 this.el.endMeasure();
26508 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26512 * Sets this button's click handler
26513 * @param {Function} handler The function to call when the button is clicked
26514 * @param {Object} scope (optional) Scope for the function passed above
26516 setHandler : function(handler, scope){
26517 this.handler = handler;
26518 this.scope = scope;
26522 * Sets this button's arrow click handler
26523 * @param {Function} handler The function to call when the arrow is clicked
26524 * @param {Object} scope (optional) Scope for the function passed above
26526 setArrowHandler : function(handler, scope){
26527 this.arrowHandler = handler;
26528 this.scope = scope;
26534 focus : function(){
26536 this.el.child("button:first").focus();
26541 onClick : function(e){
26542 e.preventDefault();
26543 if(!this.disabled){
26544 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26545 if(this.menu && !this.menu.isVisible()){
26546 this.menu.show(this.el, this.menuAlign);
26548 this.fireEvent("arrowclick", this, e);
26549 if(this.arrowHandler){
26550 this.arrowHandler.call(this.scope || this, this, e);
26553 this.fireEvent("click", this, e);
26555 this.handler.call(this.scope || this, this, e);
26561 onMouseDown : function(e){
26562 if(!this.disabled){
26563 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26567 onMouseUp : function(e){
26568 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26573 // backwards compat
26574 Roo.MenuButton = Roo.SplitButton;/*
26576 * Ext JS Library 1.1.1
26577 * Copyright(c) 2006-2007, Ext JS, LLC.
26579 * Originally Released Under LGPL - original licence link has changed is not relivant.
26582 * <script type="text/javascript">
26586 * @class Roo.Toolbar
26587 * Basic Toolbar class.
26589 * Creates a new Toolbar
26590 * @param {Object} config The config object
26592 Roo.Toolbar = function(container, buttons, config)
26594 /// old consturctor format still supported..
26595 if(container instanceof Array){ // omit the container for later rendering
26596 buttons = container;
26600 if (typeof(container) == 'object' && container.xtype) {
26601 config = container;
26602 container = config.container;
26603 buttons = config.buttons; // not really - use items!!
26606 if (config && config.items) {
26607 xitems = config.items;
26608 delete config.items;
26610 Roo.apply(this, config);
26611 this.buttons = buttons;
26614 this.render(container);
26616 Roo.each(xitems, function(b) {
26622 Roo.Toolbar.prototype = {
26624 * @cfg {Roo.data.Store} items
26625 * array of button configs or elements to add
26629 * @cfg {String/HTMLElement/Element} container
26630 * The id or element that will contain the toolbar
26633 render : function(ct){
26634 this.el = Roo.get(ct);
26636 this.el.addClass(this.cls);
26638 // using a table allows for vertical alignment
26639 // 100% width is needed by Safari...
26640 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26641 this.tr = this.el.child("tr", true);
26643 this.items = new Roo.util.MixedCollection(false, function(o){
26644 return o.id || ("item" + (++autoId));
26647 this.add.apply(this, this.buttons);
26648 delete this.buttons;
26653 * Adds element(s) to the toolbar -- this function takes a variable number of
26654 * arguments of mixed type and adds them to the toolbar.
26655 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26657 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26658 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26659 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26660 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26661 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26662 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26663 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26664 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26665 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26667 * @param {Mixed} arg2
26668 * @param {Mixed} etc.
26671 var a = arguments, l = a.length;
26672 for(var i = 0; i < l; i++){
26677 _add : function(el) {
26680 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26683 if (el.applyTo){ // some kind of form field
26684 return this.addField(el);
26686 if (el.render){ // some kind of Toolbar.Item
26687 return this.addItem(el);
26689 if (typeof el == "string"){ // string
26690 if(el == "separator" || el == "-"){
26691 return this.addSeparator();
26694 return this.addSpacer();
26697 return this.addFill();
26699 return this.addText(el);
26702 if(el.tagName){ // element
26703 return this.addElement(el);
26705 if(typeof el == "object"){ // must be button config?
26706 return this.addButton(el);
26708 // and now what?!?!
26714 * Add an Xtype element
26715 * @param {Object} xtype Xtype Object
26716 * @return {Object} created Object
26718 addxtype : function(e){
26719 return this.add(e);
26723 * Returns the Element for this toolbar.
26724 * @return {Roo.Element}
26726 getEl : function(){
26732 * @return {Roo.Toolbar.Item} The separator item
26734 addSeparator : function(){
26735 return this.addItem(new Roo.Toolbar.Separator());
26739 * Adds a spacer element
26740 * @return {Roo.Toolbar.Spacer} The spacer item
26742 addSpacer : function(){
26743 return this.addItem(new Roo.Toolbar.Spacer());
26747 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26748 * @return {Roo.Toolbar.Fill} The fill item
26750 addFill : function(){
26751 return this.addItem(new Roo.Toolbar.Fill());
26755 * Adds any standard HTML element to the toolbar
26756 * @param {String/HTMLElement/Element} el The element or id of the element to add
26757 * @return {Roo.Toolbar.Item} The element's item
26759 addElement : function(el){
26760 return this.addItem(new Roo.Toolbar.Item(el));
26763 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26764 * @type Roo.util.MixedCollection
26769 * Adds any Toolbar.Item or subclass
26770 * @param {Roo.Toolbar.Item} item
26771 * @return {Roo.Toolbar.Item} The item
26773 addItem : function(item){
26774 var td = this.nextBlock();
26776 this.items.add(item);
26781 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26782 * @param {Object/Array} config A button config or array of configs
26783 * @return {Roo.Toolbar.Button/Array}
26785 addButton : function(config){
26786 if(config instanceof Array){
26788 for(var i = 0, len = config.length; i < len; i++) {
26789 buttons.push(this.addButton(config[i]));
26794 if(!(config instanceof Roo.Toolbar.Button)){
26796 new Roo.Toolbar.SplitButton(config) :
26797 new Roo.Toolbar.Button(config);
26799 var td = this.nextBlock();
26806 * Adds text to the toolbar
26807 * @param {String} text The text to add
26808 * @return {Roo.Toolbar.Item} The element's item
26810 addText : function(text){
26811 return this.addItem(new Roo.Toolbar.TextItem(text));
26815 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26816 * @param {Number} index The index where the item is to be inserted
26817 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26818 * @return {Roo.Toolbar.Button/Item}
26820 insertButton : function(index, item){
26821 if(item instanceof Array){
26823 for(var i = 0, len = item.length; i < len; i++) {
26824 buttons.push(this.insertButton(index + i, item[i]));
26828 if (!(item instanceof Roo.Toolbar.Button)){
26829 item = new Roo.Toolbar.Button(item);
26831 var td = document.createElement("td");
26832 this.tr.insertBefore(td, this.tr.childNodes[index]);
26834 this.items.insert(index, item);
26839 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26840 * @param {Object} config
26841 * @return {Roo.Toolbar.Item} The element's item
26843 addDom : function(config, returnEl){
26844 var td = this.nextBlock();
26845 Roo.DomHelper.overwrite(td, config);
26846 var ti = new Roo.Toolbar.Item(td.firstChild);
26848 this.items.add(ti);
26853 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26854 * @type Roo.util.MixedCollection
26859 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26860 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26861 * @param {Roo.form.Field} field
26862 * @return {Roo.ToolbarItem}
26866 addField : function(field) {
26867 if (!this.fields) {
26869 this.fields = new Roo.util.MixedCollection(false, function(o){
26870 return o.id || ("item" + (++autoId));
26875 var td = this.nextBlock();
26877 var ti = new Roo.Toolbar.Item(td.firstChild);
26879 this.items.add(ti);
26880 this.fields.add(field);
26891 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26892 this.el.child('div').hide();
26900 this.el.child('div').show();
26904 nextBlock : function(){
26905 var td = document.createElement("td");
26906 this.tr.appendChild(td);
26911 destroy : function(){
26912 if(this.items){ // rendered?
26913 Roo.destroy.apply(Roo, this.items.items);
26915 if(this.fields){ // rendered?
26916 Roo.destroy.apply(Roo, this.fields.items);
26918 Roo.Element.uncache(this.el, this.tr);
26923 * @class Roo.Toolbar.Item
26924 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26926 * Creates a new Item
26927 * @param {HTMLElement} el
26929 Roo.Toolbar.Item = function(el){
26930 this.el = Roo.getDom(el);
26931 this.id = Roo.id(this.el);
26932 this.hidden = false;
26935 Roo.Toolbar.Item.prototype = {
26938 * Get this item's HTML Element
26939 * @return {HTMLElement}
26941 getEl : function(){
26946 render : function(td){
26948 td.appendChild(this.el);
26952 * Removes and destroys this item.
26954 destroy : function(){
26955 this.td.parentNode.removeChild(this.td);
26962 this.hidden = false;
26963 this.td.style.display = "";
26970 this.hidden = true;
26971 this.td.style.display = "none";
26975 * Convenience function for boolean show/hide.
26976 * @param {Boolean} visible true to show/false to hide
26978 setVisible: function(visible){
26987 * Try to focus this item.
26989 focus : function(){
26990 Roo.fly(this.el).focus();
26994 * Disables this item.
26996 disable : function(){
26997 Roo.fly(this.td).addClass("x-item-disabled");
26998 this.disabled = true;
26999 this.el.disabled = true;
27003 * Enables this item.
27005 enable : function(){
27006 Roo.fly(this.td).removeClass("x-item-disabled");
27007 this.disabled = false;
27008 this.el.disabled = false;
27014 * @class Roo.Toolbar.Separator
27015 * @extends Roo.Toolbar.Item
27016 * A simple toolbar separator class
27018 * Creates a new Separator
27020 Roo.Toolbar.Separator = function(){
27021 var s = document.createElement("span");
27022 s.className = "ytb-sep";
27023 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27025 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27026 enable:Roo.emptyFn,
27027 disable:Roo.emptyFn,
27032 * @class Roo.Toolbar.Spacer
27033 * @extends Roo.Toolbar.Item
27034 * A simple element that adds extra horizontal space to a toolbar.
27036 * Creates a new Spacer
27038 Roo.Toolbar.Spacer = function(){
27039 var s = document.createElement("div");
27040 s.className = "ytb-spacer";
27041 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27043 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27044 enable:Roo.emptyFn,
27045 disable:Roo.emptyFn,
27050 * @class Roo.Toolbar.Fill
27051 * @extends Roo.Toolbar.Spacer
27052 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27054 * Creates a new Spacer
27056 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27058 render : function(td){
27059 td.style.width = '100%';
27060 Roo.Toolbar.Fill.superclass.render.call(this, td);
27065 * @class Roo.Toolbar.TextItem
27066 * @extends Roo.Toolbar.Item
27067 * A simple class that renders text directly into a toolbar.
27069 * Creates a new TextItem
27070 * @param {String} text
27072 Roo.Toolbar.TextItem = function(text){
27073 if (typeof(text) == 'object') {
27076 var s = document.createElement("span");
27077 s.className = "ytb-text";
27078 s.innerHTML = text;
27079 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27081 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27082 enable:Roo.emptyFn,
27083 disable:Roo.emptyFn,
27088 * @class Roo.Toolbar.Button
27089 * @extends Roo.Button
27090 * A button that renders into a toolbar.
27092 * Creates a new Button
27093 * @param {Object} config A standard {@link Roo.Button} config object
27095 Roo.Toolbar.Button = function(config){
27096 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27098 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27099 render : function(td){
27101 Roo.Toolbar.Button.superclass.render.call(this, td);
27105 * Removes and destroys this button
27107 destroy : function(){
27108 Roo.Toolbar.Button.superclass.destroy.call(this);
27109 this.td.parentNode.removeChild(this.td);
27113 * Shows this button
27116 this.hidden = false;
27117 this.td.style.display = "";
27121 * Hides this button
27124 this.hidden = true;
27125 this.td.style.display = "none";
27129 * Disables this item
27131 disable : function(){
27132 Roo.fly(this.td).addClass("x-item-disabled");
27133 this.disabled = true;
27137 * Enables this item
27139 enable : function(){
27140 Roo.fly(this.td).removeClass("x-item-disabled");
27141 this.disabled = false;
27144 // backwards compat
27145 Roo.ToolbarButton = Roo.Toolbar.Button;
27148 * @class Roo.Toolbar.SplitButton
27149 * @extends Roo.SplitButton
27150 * A menu button that renders into a toolbar.
27152 * Creates a new SplitButton
27153 * @param {Object} config A standard {@link Roo.SplitButton} config object
27155 Roo.Toolbar.SplitButton = function(config){
27156 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27158 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27159 render : function(td){
27161 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27165 * Removes and destroys this button
27167 destroy : function(){
27168 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27169 this.td.parentNode.removeChild(this.td);
27173 * Shows this button
27176 this.hidden = false;
27177 this.td.style.display = "";
27181 * Hides this button
27184 this.hidden = true;
27185 this.td.style.display = "none";
27189 // backwards compat
27190 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27192 * Ext JS Library 1.1.1
27193 * Copyright(c) 2006-2007, Ext JS, LLC.
27195 * Originally Released Under LGPL - original licence link has changed is not relivant.
27198 * <script type="text/javascript">
27202 * @class Roo.PagingToolbar
27203 * @extends Roo.Toolbar
27204 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27206 * Create a new PagingToolbar
27207 * @param {Object} config The config object
27209 Roo.PagingToolbar = function(el, ds, config)
27211 // old args format still supported... - xtype is prefered..
27212 if (typeof(el) == 'object' && el.xtype) {
27213 // created from xtype...
27215 ds = el.dataSource;
27216 el = config.container;
27219 if (config.items) {
27220 items = config.items;
27224 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27227 this.renderButtons(this.el);
27230 // supprot items array.
27232 Roo.each(items, function(e) {
27233 this.add(Roo.factory(e));
27238 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27240 * @cfg {Roo.data.Store} dataSource
27241 * The underlying data store providing the paged data
27244 * @cfg {String/HTMLElement/Element} container
27245 * container The id or element that will contain the toolbar
27248 * @cfg {Boolean} displayInfo
27249 * True to display the displayMsg (defaults to false)
27252 * @cfg {Number} pageSize
27253 * The number of records to display per page (defaults to 20)
27257 * @cfg {String} displayMsg
27258 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27260 displayMsg : 'Displaying {0} - {1} of {2}',
27262 * @cfg {String} emptyMsg
27263 * The message to display when no records are found (defaults to "No data to display")
27265 emptyMsg : 'No data to display',
27267 * Customizable piece of the default paging text (defaults to "Page")
27270 beforePageText : "Page",
27272 * Customizable piece of the default paging text (defaults to "of %0")
27275 afterPageText : "of {0}",
27277 * Customizable piece of the default paging text (defaults to "First Page")
27280 firstText : "First Page",
27282 * Customizable piece of the default paging text (defaults to "Previous Page")
27285 prevText : "Previous Page",
27287 * Customizable piece of the default paging text (defaults to "Next Page")
27290 nextText : "Next Page",
27292 * Customizable piece of the default paging text (defaults to "Last Page")
27295 lastText : "Last Page",
27297 * Customizable piece of the default paging text (defaults to "Refresh")
27300 refreshText : "Refresh",
27303 renderButtons : function(el){
27304 Roo.PagingToolbar.superclass.render.call(this, el);
27305 this.first = this.addButton({
27306 tooltip: this.firstText,
27307 cls: "x-btn-icon x-grid-page-first",
27309 handler: this.onClick.createDelegate(this, ["first"])
27311 this.prev = this.addButton({
27312 tooltip: this.prevText,
27313 cls: "x-btn-icon x-grid-page-prev",
27315 handler: this.onClick.createDelegate(this, ["prev"])
27317 //this.addSeparator();
27318 this.add(this.beforePageText);
27319 this.field = Roo.get(this.addDom({
27324 cls: "x-grid-page-number"
27326 this.field.on("keydown", this.onPagingKeydown, this);
27327 this.field.on("focus", function(){this.dom.select();});
27328 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27329 this.field.setHeight(18);
27330 //this.addSeparator();
27331 this.next = this.addButton({
27332 tooltip: this.nextText,
27333 cls: "x-btn-icon x-grid-page-next",
27335 handler: this.onClick.createDelegate(this, ["next"])
27337 this.last = this.addButton({
27338 tooltip: this.lastText,
27339 cls: "x-btn-icon x-grid-page-last",
27341 handler: this.onClick.createDelegate(this, ["last"])
27343 //this.addSeparator();
27344 this.loading = this.addButton({
27345 tooltip: this.refreshText,
27346 cls: "x-btn-icon x-grid-loading",
27347 handler: this.onClick.createDelegate(this, ["refresh"])
27350 if(this.displayInfo){
27351 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27356 updateInfo : function(){
27357 if(this.displayEl){
27358 var count = this.ds.getCount();
27359 var msg = count == 0 ?
27363 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27365 this.displayEl.update(msg);
27370 onLoad : function(ds, r, o){
27371 this.cursor = o.params ? o.params.start : 0;
27372 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27374 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27375 this.field.dom.value = ap;
27376 this.first.setDisabled(ap == 1);
27377 this.prev.setDisabled(ap == 1);
27378 this.next.setDisabled(ap == ps);
27379 this.last.setDisabled(ap == ps);
27380 this.loading.enable();
27385 getPageData : function(){
27386 var total = this.ds.getTotalCount();
27389 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27390 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27395 onLoadError : function(){
27396 this.loading.enable();
27400 onPagingKeydown : function(e){
27401 var k = e.getKey();
27402 var d = this.getPageData();
27404 var v = this.field.dom.value, pageNum;
27405 if(!v || isNaN(pageNum = parseInt(v, 10))){
27406 this.field.dom.value = d.activePage;
27409 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27410 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27413 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))
27415 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27416 this.field.dom.value = pageNum;
27417 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27420 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27422 var v = this.field.dom.value, pageNum;
27423 var increment = (e.shiftKey) ? 10 : 1;
27424 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27426 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27427 this.field.dom.value = d.activePage;
27430 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27432 this.field.dom.value = parseInt(v, 10) + increment;
27433 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27434 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27441 beforeLoad : function(){
27443 this.loading.disable();
27448 onClick : function(which){
27452 ds.load({params:{start: 0, limit: this.pageSize}});
27455 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27458 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27461 var total = ds.getTotalCount();
27462 var extra = total % this.pageSize;
27463 var lastStart = extra ? (total - extra) : total-this.pageSize;
27464 ds.load({params:{start: lastStart, limit: this.pageSize}});
27467 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27473 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27474 * @param {Roo.data.Store} store The data store to unbind
27476 unbind : function(ds){
27477 ds.un("beforeload", this.beforeLoad, this);
27478 ds.un("load", this.onLoad, this);
27479 ds.un("loadexception", this.onLoadError, this);
27480 ds.un("remove", this.updateInfo, this);
27481 ds.un("add", this.updateInfo, this);
27482 this.ds = undefined;
27486 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27487 * @param {Roo.data.Store} store The data store to bind
27489 bind : function(ds){
27490 ds.on("beforeload", this.beforeLoad, this);
27491 ds.on("load", this.onLoad, this);
27492 ds.on("loadexception", this.onLoadError, this);
27493 ds.on("remove", this.updateInfo, this);
27494 ds.on("add", this.updateInfo, this);
27499 * Ext JS Library 1.1.1
27500 * Copyright(c) 2006-2007, Ext JS, LLC.
27502 * Originally Released Under LGPL - original licence link has changed is not relivant.
27505 * <script type="text/javascript">
27509 * @class Roo.Resizable
27510 * @extends Roo.util.Observable
27511 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27512 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27513 * 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
27514 * the element will be wrapped for you automatically.</p>
27515 * <p>Here is the list of valid resize handles:</p>
27518 ------ -------------------
27527 'hd' horizontal drag
27530 * <p>Here's an example showing the creation of a typical Resizable:</p>
27532 var resizer = new Roo.Resizable("element-id", {
27540 resizer.on("resize", myHandler);
27542 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27543 * resizer.east.setDisplayed(false);</p>
27544 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27545 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27546 * resize operation's new size (defaults to [0, 0])
27547 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27548 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27549 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27550 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27551 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27552 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27553 * @cfg {Number} width The width of the element in pixels (defaults to null)
27554 * @cfg {Number} height The height of the element in pixels (defaults to null)
27555 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27556 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27557 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27558 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27559 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27560 * in favor of the handles config option (defaults to false)
27561 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27562 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27563 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27564 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27565 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27566 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27567 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27568 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27569 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27570 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27571 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27573 * Create a new resizable component
27574 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27575 * @param {Object} config configuration options
27577 Roo.Resizable = function(el, config)
27579 this.el = Roo.get(el);
27581 if(config && config.wrap){
27582 config.resizeChild = this.el;
27583 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27584 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27585 this.el.setStyle("overflow", "hidden");
27586 this.el.setPositioning(config.resizeChild.getPositioning());
27587 config.resizeChild.clearPositioning();
27588 if(!config.width || !config.height){
27589 var csize = config.resizeChild.getSize();
27590 this.el.setSize(csize.width, csize.height);
27592 if(config.pinned && !config.adjustments){
27593 config.adjustments = "auto";
27597 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27598 this.proxy.unselectable();
27599 this.proxy.enableDisplayMode('block');
27601 Roo.apply(this, config);
27604 this.disableTrackOver = true;
27605 this.el.addClass("x-resizable-pinned");
27607 // if the element isn't positioned, make it relative
27608 var position = this.el.getStyle("position");
27609 if(position != "absolute" && position != "fixed"){
27610 this.el.setStyle("position", "relative");
27612 if(!this.handles){ // no handles passed, must be legacy style
27613 this.handles = 's,e,se';
27614 if(this.multiDirectional){
27615 this.handles += ',n,w';
27618 if(this.handles == "all"){
27619 this.handles = "n s e w ne nw se sw";
27621 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27622 var ps = Roo.Resizable.positions;
27623 for(var i = 0, len = hs.length; i < len; i++){
27624 if(hs[i] && ps[hs[i]]){
27625 var pos = ps[hs[i]];
27626 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27630 this.corner = this.southeast;
27632 // updateBox = the box can move..
27633 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27634 this.updateBox = true;
27637 this.activeHandle = null;
27639 if(this.resizeChild){
27640 if(typeof this.resizeChild == "boolean"){
27641 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27643 this.resizeChild = Roo.get(this.resizeChild, true);
27647 if(this.adjustments == "auto"){
27648 var rc = this.resizeChild;
27649 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27650 if(rc && (hw || hn)){
27651 rc.position("relative");
27652 rc.setLeft(hw ? hw.el.getWidth() : 0);
27653 rc.setTop(hn ? hn.el.getHeight() : 0);
27655 this.adjustments = [
27656 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27657 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27661 if(this.draggable){
27662 this.dd = this.dynamic ?
27663 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27664 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27670 * @event beforeresize
27671 * Fired before resize is allowed. Set enabled to false to cancel resize.
27672 * @param {Roo.Resizable} this
27673 * @param {Roo.EventObject} e The mousedown event
27675 "beforeresize" : true,
27678 * Fired after a resize.
27679 * @param {Roo.Resizable} this
27680 * @param {Number} width The new width
27681 * @param {Number} height The new height
27682 * @param {Roo.EventObject} e The mouseup event
27687 if(this.width !== null && this.height !== null){
27688 this.resizeTo(this.width, this.height);
27690 this.updateChildSize();
27693 this.el.dom.style.zoom = 1;
27695 Roo.Resizable.superclass.constructor.call(this);
27698 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27699 resizeChild : false,
27700 adjustments : [0, 0],
27710 multiDirectional : false,
27711 disableTrackOver : false,
27712 easing : 'easeOutStrong',
27713 widthIncrement : 0,
27714 heightIncrement : 0,
27718 preserveRatio : false,
27719 transparent: false,
27725 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27727 constrainTo: undefined,
27729 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27731 resizeRegion: undefined,
27735 * Perform a manual resize
27736 * @param {Number} width
27737 * @param {Number} height
27739 resizeTo : function(width, height){
27740 this.el.setSize(width, height);
27741 this.updateChildSize();
27742 this.fireEvent("resize", this, width, height, null);
27746 startSizing : function(e, handle){
27747 this.fireEvent("beforeresize", this, e);
27748 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27751 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27752 this.overlay.unselectable();
27753 this.overlay.enableDisplayMode("block");
27754 this.overlay.on("mousemove", this.onMouseMove, this);
27755 this.overlay.on("mouseup", this.onMouseUp, this);
27757 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27759 this.resizing = true;
27760 this.startBox = this.el.getBox();
27761 this.startPoint = e.getXY();
27762 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27763 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27765 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27766 this.overlay.show();
27768 if(this.constrainTo) {
27769 var ct = Roo.get(this.constrainTo);
27770 this.resizeRegion = ct.getRegion().adjust(
27771 ct.getFrameWidth('t'),
27772 ct.getFrameWidth('l'),
27773 -ct.getFrameWidth('b'),
27774 -ct.getFrameWidth('r')
27778 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27780 this.proxy.setBox(this.startBox);
27782 this.proxy.setStyle('visibility', 'visible');
27788 onMouseDown : function(handle, e){
27791 this.activeHandle = handle;
27792 this.startSizing(e, handle);
27797 onMouseUp : function(e){
27798 var size = this.resizeElement();
27799 this.resizing = false;
27801 this.overlay.hide();
27803 this.fireEvent("resize", this, size.width, size.height, e);
27807 updateChildSize : function(){
27808 if(this.resizeChild){
27810 var child = this.resizeChild;
27811 var adj = this.adjustments;
27812 if(el.dom.offsetWidth){
27813 var b = el.getSize(true);
27814 child.setSize(b.width+adj[0], b.height+adj[1]);
27816 // Second call here for IE
27817 // The first call enables instant resizing and
27818 // the second call corrects scroll bars if they
27821 setTimeout(function(){
27822 if(el.dom.offsetWidth){
27823 var b = el.getSize(true);
27824 child.setSize(b.width+adj[0], b.height+adj[1]);
27832 snap : function(value, inc, min){
27833 if(!inc || !value) return value;
27834 var newValue = value;
27835 var m = value % inc;
27838 newValue = value + (inc-m);
27840 newValue = value - m;
27843 return Math.max(min, newValue);
27847 resizeElement : function(){
27848 var box = this.proxy.getBox();
27849 if(this.updateBox){
27850 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27852 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27854 this.updateChildSize();
27862 constrain : function(v, diff, m, mx){
27865 }else if(v - diff > mx){
27872 onMouseMove : function(e){
27874 try{// try catch so if something goes wrong the user doesn't get hung
27876 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27880 //var curXY = this.startPoint;
27881 var curSize = this.curSize || this.startBox;
27882 var x = this.startBox.x, y = this.startBox.y;
27883 var ox = x, oy = y;
27884 var w = curSize.width, h = curSize.height;
27885 var ow = w, oh = h;
27886 var mw = this.minWidth, mh = this.minHeight;
27887 var mxw = this.maxWidth, mxh = this.maxHeight;
27888 var wi = this.widthIncrement;
27889 var hi = this.heightIncrement;
27891 var eventXY = e.getXY();
27892 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27893 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27895 var pos = this.activeHandle.position;
27900 w = Math.min(Math.max(mw, w), mxw);
27905 h = Math.min(Math.max(mh, h), mxh);
27910 w = Math.min(Math.max(mw, w), mxw);
27911 h = Math.min(Math.max(mh, h), mxh);
27914 diffY = this.constrain(h, diffY, mh, mxh);
27921 var adiffX = Math.abs(diffX);
27922 var sub = (adiffX % wi); // how much
27923 if (sub > (wi/2)) { // far enough to snap
27924 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
27926 // remove difference..
27927 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
27931 x = Math.max(this.minX, x);
27934 diffX = this.constrain(w, diffX, mw, mxw);
27940 w = Math.min(Math.max(mw, w), mxw);
27941 diffY = this.constrain(h, diffY, mh, mxh);
27946 diffX = this.constrain(w, diffX, mw, mxw);
27947 diffY = this.constrain(h, diffY, mh, mxh);
27954 diffX = this.constrain(w, diffX, mw, mxw);
27956 h = Math.min(Math.max(mh, h), mxh);
27962 var sw = this.snap(w, wi, mw);
27963 var sh = this.snap(h, hi, mh);
27964 if(sw != w || sh != h){
27987 if(this.preserveRatio){
27992 h = Math.min(Math.max(mh, h), mxh);
27997 w = Math.min(Math.max(mw, w), mxw);
28002 w = Math.min(Math.max(mw, w), mxw);
28008 w = Math.min(Math.max(mw, w), mxw);
28014 h = Math.min(Math.max(mh, h), mxh);
28022 h = Math.min(Math.max(mh, h), mxh);
28032 h = Math.min(Math.max(mh, h), mxh);
28040 if (pos == 'hdrag') {
28043 this.proxy.setBounds(x, y, w, h);
28045 this.resizeElement();
28052 handleOver : function(){
28054 this.el.addClass("x-resizable-over");
28059 handleOut : function(){
28060 if(!this.resizing){
28061 this.el.removeClass("x-resizable-over");
28066 * Returns the element this component is bound to.
28067 * @return {Roo.Element}
28069 getEl : function(){
28074 * Returns the resizeChild element (or null).
28075 * @return {Roo.Element}
28077 getResizeChild : function(){
28078 return this.resizeChild;
28082 * Destroys this resizable. If the element was wrapped and
28083 * removeEl is not true then the element remains.
28084 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28086 destroy : function(removeEl){
28087 this.proxy.remove();
28089 this.overlay.removeAllListeners();
28090 this.overlay.remove();
28092 var ps = Roo.Resizable.positions;
28094 if(typeof ps[k] != "function" && this[ps[k]]){
28095 var h = this[ps[k]];
28096 h.el.removeAllListeners();
28101 this.el.update("");
28108 // hash to map config positions to true positions
28109 Roo.Resizable.positions = {
28110 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28115 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28117 // only initialize the template if resizable is used
28118 var tpl = Roo.DomHelper.createTemplate(
28119 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28122 Roo.Resizable.Handle.prototype.tpl = tpl;
28124 this.position = pos;
28126 // show north drag fro topdra
28127 var handlepos = pos == 'hdrag' ? 'north' : pos;
28129 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28130 if (pos == 'hdrag') {
28131 this.el.setStyle('cursor', 'pointer');
28133 this.el.unselectable();
28135 this.el.setOpacity(0);
28137 this.el.on("mousedown", this.onMouseDown, this);
28138 if(!disableTrackOver){
28139 this.el.on("mouseover", this.onMouseOver, this);
28140 this.el.on("mouseout", this.onMouseOut, this);
28145 Roo.Resizable.Handle.prototype = {
28146 afterResize : function(rz){
28150 onMouseDown : function(e){
28151 this.rz.onMouseDown(this, e);
28154 onMouseOver : function(e){
28155 this.rz.handleOver(this, e);
28158 onMouseOut : function(e){
28159 this.rz.handleOut(this, e);
28163 * Ext JS Library 1.1.1
28164 * Copyright(c) 2006-2007, Ext JS, LLC.
28166 * Originally Released Under LGPL - original licence link has changed is not relivant.
28169 * <script type="text/javascript">
28173 * @class Roo.Editor
28174 * @extends Roo.Component
28175 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28177 * Create a new Editor
28178 * @param {Roo.form.Field} field The Field object (or descendant)
28179 * @param {Object} config The config object
28181 Roo.Editor = function(field, config){
28182 Roo.Editor.superclass.constructor.call(this, config);
28183 this.field = field;
28186 * @event beforestartedit
28187 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28188 * false from the handler of this event.
28189 * @param {Editor} this
28190 * @param {Roo.Element} boundEl The underlying element bound to this editor
28191 * @param {Mixed} value The field value being set
28193 "beforestartedit" : true,
28196 * Fires when this editor is displayed
28197 * @param {Roo.Element} boundEl The underlying element bound to this editor
28198 * @param {Mixed} value The starting field value
28200 "startedit" : true,
28202 * @event beforecomplete
28203 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28204 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28205 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28206 * event will not fire since no edit actually occurred.
28207 * @param {Editor} this
28208 * @param {Mixed} value The current field value
28209 * @param {Mixed} startValue The original field value
28211 "beforecomplete" : true,
28214 * Fires after editing is complete and any changed value has been written to the underlying field.
28215 * @param {Editor} this
28216 * @param {Mixed} value The current field value
28217 * @param {Mixed} startValue The original field value
28221 * @event specialkey
28222 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28223 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28224 * @param {Roo.form.Field} this
28225 * @param {Roo.EventObject} e The event object
28227 "specialkey" : true
28231 Roo.extend(Roo.Editor, Roo.Component, {
28233 * @cfg {Boolean/String} autosize
28234 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28235 * or "height" to adopt the height only (defaults to false)
28238 * @cfg {Boolean} revertInvalid
28239 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28240 * validation fails (defaults to true)
28243 * @cfg {Boolean} ignoreNoChange
28244 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28245 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28246 * will never be ignored.
28249 * @cfg {Boolean} hideEl
28250 * False to keep the bound element visible while the editor is displayed (defaults to true)
28253 * @cfg {Mixed} value
28254 * The data value of the underlying field (defaults to "")
28258 * @cfg {String} alignment
28259 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28263 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28264 * for bottom-right shadow (defaults to "frame")
28268 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28272 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28274 completeOnEnter : false,
28276 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28278 cancelOnEsc : false,
28280 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28285 onRender : function(ct, position){
28286 this.el = new Roo.Layer({
28287 shadow: this.shadow,
28293 constrain: this.constrain
28295 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28296 if(this.field.msgTarget != 'title'){
28297 this.field.msgTarget = 'qtip';
28299 this.field.render(this.el);
28301 this.field.el.dom.setAttribute('autocomplete', 'off');
28303 this.field.on("specialkey", this.onSpecialKey, this);
28304 if(this.swallowKeys){
28305 this.field.el.swallowEvent(['keydown','keypress']);
28308 this.field.on("blur", this.onBlur, this);
28309 if(this.field.grow){
28310 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28314 onSpecialKey : function(field, e)
28316 //Roo.log('editor onSpecialKey');
28317 if(this.completeOnEnter && e.getKey() == e.ENTER){
28319 this.completeEdit();
28322 // do not fire special key otherwise it might hide close the editor...
28323 if(e.getKey() == e.ENTER){
28326 if(this.cancelOnEsc && e.getKey() == e.ESC){
28330 this.fireEvent('specialkey', field, e);
28335 * Starts the editing process and shows the editor.
28336 * @param {String/HTMLElement/Element} el The element to edit
28337 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28338 * to the innerHTML of el.
28340 startEdit : function(el, value){
28342 this.completeEdit();
28344 this.boundEl = Roo.get(el);
28345 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28346 if(!this.rendered){
28347 this.render(this.parentEl || document.body);
28349 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28352 this.startValue = v;
28353 this.field.setValue(v);
28355 var sz = this.boundEl.getSize();
28356 switch(this.autoSize){
28358 this.setSize(sz.width, "");
28361 this.setSize("", sz.height);
28364 this.setSize(sz.width, sz.height);
28367 this.el.alignTo(this.boundEl, this.alignment);
28368 this.editing = true;
28370 Roo.QuickTips.disable();
28376 * Sets the height and width of this editor.
28377 * @param {Number} width The new width
28378 * @param {Number} height The new height
28380 setSize : function(w, h){
28381 this.field.setSize(w, h);
28388 * Realigns the editor to the bound field based on the current alignment config value.
28390 realign : function(){
28391 this.el.alignTo(this.boundEl, this.alignment);
28395 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28396 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28398 completeEdit : function(remainVisible){
28402 var v = this.getValue();
28403 if(this.revertInvalid !== false && !this.field.isValid()){
28404 v = this.startValue;
28405 this.cancelEdit(true);
28407 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28408 this.editing = false;
28412 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28413 this.editing = false;
28414 if(this.updateEl && this.boundEl){
28415 this.boundEl.update(v);
28417 if(remainVisible !== true){
28420 this.fireEvent("complete", this, v, this.startValue);
28425 onShow : function(){
28427 if(this.hideEl !== false){
28428 this.boundEl.hide();
28431 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28432 this.fixIEFocus = true;
28433 this.deferredFocus.defer(50, this);
28435 this.field.focus();
28437 this.fireEvent("startedit", this.boundEl, this.startValue);
28440 deferredFocus : function(){
28442 this.field.focus();
28447 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28448 * reverted to the original starting value.
28449 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28450 * cancel (defaults to false)
28452 cancelEdit : function(remainVisible){
28454 this.setValue(this.startValue);
28455 if(remainVisible !== true){
28462 onBlur : function(){
28463 if(this.allowBlur !== true && this.editing){
28464 this.completeEdit();
28469 onHide : function(){
28471 this.completeEdit();
28475 if(this.field.collapse){
28476 this.field.collapse();
28479 if(this.hideEl !== false){
28480 this.boundEl.show();
28483 Roo.QuickTips.enable();
28488 * Sets the data value of the editor
28489 * @param {Mixed} value Any valid value supported by the underlying field
28491 setValue : function(v){
28492 this.field.setValue(v);
28496 * Gets the data value of the editor
28497 * @return {Mixed} The data value
28499 getValue : function(){
28500 return this.field.getValue();
28504 * Ext JS Library 1.1.1
28505 * Copyright(c) 2006-2007, Ext JS, LLC.
28507 * Originally Released Under LGPL - original licence link has changed is not relivant.
28510 * <script type="text/javascript">
28514 * @class Roo.BasicDialog
28515 * @extends Roo.util.Observable
28516 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28518 var dlg = new Roo.BasicDialog("my-dlg", {
28527 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28528 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28529 dlg.addButton('Cancel', dlg.hide, dlg);
28532 <b>A Dialog should always be a direct child of the body element.</b>
28533 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28534 * @cfg {String} title Default text to display in the title bar (defaults to null)
28535 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28536 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28537 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28538 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28539 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28540 * (defaults to null with no animation)
28541 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28542 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28543 * property for valid values (defaults to 'all')
28544 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28545 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28546 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28547 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28548 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28549 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28550 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28551 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28552 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28553 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28554 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28555 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28556 * draggable = true (defaults to false)
28557 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28558 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28559 * shadow (defaults to false)
28560 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28561 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28562 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28563 * @cfg {Array} buttons Array of buttons
28564 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28566 * Create a new BasicDialog.
28567 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28568 * @param {Object} config Configuration options
28570 Roo.BasicDialog = function(el, config){
28571 this.el = Roo.get(el);
28572 var dh = Roo.DomHelper;
28573 if(!this.el && config && config.autoCreate){
28574 if(typeof config.autoCreate == "object"){
28575 if(!config.autoCreate.id){
28576 config.autoCreate.id = el;
28578 this.el = dh.append(document.body,
28579 config.autoCreate, true);
28581 this.el = dh.append(document.body,
28582 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28586 el.setDisplayed(true);
28587 el.hide = this.hideAction;
28589 el.addClass("x-dlg");
28591 Roo.apply(this, config);
28593 this.proxy = el.createProxy("x-dlg-proxy");
28594 this.proxy.hide = this.hideAction;
28595 this.proxy.setOpacity(.5);
28599 el.setWidth(config.width);
28602 el.setHeight(config.height);
28604 this.size = el.getSize();
28605 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28606 this.xy = [config.x,config.y];
28608 this.xy = el.getCenterXY(true);
28610 /** The header element @type Roo.Element */
28611 this.header = el.child("> .x-dlg-hd");
28612 /** The body element @type Roo.Element */
28613 this.body = el.child("> .x-dlg-bd");
28614 /** The footer element @type Roo.Element */
28615 this.footer = el.child("> .x-dlg-ft");
28618 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28621 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28624 this.header.unselectable();
28626 this.header.update(this.title);
28628 // this element allows the dialog to be focused for keyboard event
28629 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28630 this.focusEl.swallowEvent("click", true);
28632 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28634 // wrap the body and footer for special rendering
28635 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28637 this.bwrap.dom.appendChild(this.footer.dom);
28640 this.bg = this.el.createChild({
28641 tag: "div", cls:"x-dlg-bg",
28642 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28644 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28647 if(this.autoScroll !== false && !this.autoTabs){
28648 this.body.setStyle("overflow", "auto");
28651 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28653 if(this.closable !== false){
28654 this.el.addClass("x-dlg-closable");
28655 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28656 this.close.on("click", this.closeClick, this);
28657 this.close.addClassOnOver("x-dlg-close-over");
28659 if(this.collapsible !== false){
28660 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28661 this.collapseBtn.on("click", this.collapseClick, this);
28662 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28663 this.header.on("dblclick", this.collapseClick, this);
28665 if(this.resizable !== false){
28666 this.el.addClass("x-dlg-resizable");
28667 this.resizer = new Roo.Resizable(el, {
28668 minWidth: this.minWidth || 80,
28669 minHeight:this.minHeight || 80,
28670 handles: this.resizeHandles || "all",
28673 this.resizer.on("beforeresize", this.beforeResize, this);
28674 this.resizer.on("resize", this.onResize, this);
28676 if(this.draggable !== false){
28677 el.addClass("x-dlg-draggable");
28678 if (!this.proxyDrag) {
28679 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28682 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28684 dd.setHandleElId(this.header.id);
28685 dd.endDrag = this.endMove.createDelegate(this);
28686 dd.startDrag = this.startMove.createDelegate(this);
28687 dd.onDrag = this.onDrag.createDelegate(this);
28692 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28693 this.mask.enableDisplayMode("block");
28695 this.el.addClass("x-dlg-modal");
28698 this.shadow = new Roo.Shadow({
28699 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28700 offset : this.shadowOffset
28703 this.shadowOffset = 0;
28705 if(Roo.useShims && this.shim !== false){
28706 this.shim = this.el.createShim();
28707 this.shim.hide = this.hideAction;
28715 if (this.buttons) {
28716 var bts= this.buttons;
28718 Roo.each(bts, function(b) {
28727 * Fires when a key is pressed
28728 * @param {Roo.BasicDialog} this
28729 * @param {Roo.EventObject} e
28734 * Fires when this dialog is moved by the user.
28735 * @param {Roo.BasicDialog} this
28736 * @param {Number} x The new page X
28737 * @param {Number} y The new page Y
28742 * Fires when this dialog is resized by the user.
28743 * @param {Roo.BasicDialog} this
28744 * @param {Number} width The new width
28745 * @param {Number} height The new height
28749 * @event beforehide
28750 * Fires before this dialog is hidden.
28751 * @param {Roo.BasicDialog} this
28753 "beforehide" : true,
28756 * Fires when this dialog is hidden.
28757 * @param {Roo.BasicDialog} this
28761 * @event beforeshow
28762 * Fires before this dialog is shown.
28763 * @param {Roo.BasicDialog} this
28765 "beforeshow" : true,
28768 * Fires when this dialog is shown.
28769 * @param {Roo.BasicDialog} this
28773 el.on("keydown", this.onKeyDown, this);
28774 el.on("mousedown", this.toFront, this);
28775 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28777 Roo.DialogManager.register(this);
28778 Roo.BasicDialog.superclass.constructor.call(this);
28781 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28782 shadowOffset: Roo.isIE ? 6 : 5,
28785 minButtonWidth: 75,
28786 defaultButton: null,
28787 buttonAlign: "right",
28792 * Sets the dialog title text
28793 * @param {String} text The title text to display
28794 * @return {Roo.BasicDialog} this
28796 setTitle : function(text){
28797 this.header.update(text);
28802 closeClick : function(){
28807 collapseClick : function(){
28808 this[this.collapsed ? "expand" : "collapse"]();
28812 * Collapses the dialog to its minimized state (only the title bar is visible).
28813 * Equivalent to the user clicking the collapse dialog button.
28815 collapse : function(){
28816 if(!this.collapsed){
28817 this.collapsed = true;
28818 this.el.addClass("x-dlg-collapsed");
28819 this.restoreHeight = this.el.getHeight();
28820 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28825 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28826 * clicking the expand dialog button.
28828 expand : function(){
28829 if(this.collapsed){
28830 this.collapsed = false;
28831 this.el.removeClass("x-dlg-collapsed");
28832 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28837 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28838 * @return {Roo.TabPanel} The tabs component
28840 initTabs : function(){
28841 var tabs = this.getTabs();
28842 while(tabs.getTab(0)){
28845 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28847 tabs.addTab(Roo.id(dom), dom.title);
28855 beforeResize : function(){
28856 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28860 onResize : function(){
28861 this.refreshSize();
28862 this.syncBodyHeight();
28863 this.adjustAssets();
28865 this.fireEvent("resize", this, this.size.width, this.size.height);
28869 onKeyDown : function(e){
28870 if(this.isVisible()){
28871 this.fireEvent("keydown", this, e);
28876 * Resizes the dialog.
28877 * @param {Number} width
28878 * @param {Number} height
28879 * @return {Roo.BasicDialog} this
28881 resizeTo : function(width, height){
28882 this.el.setSize(width, height);
28883 this.size = {width: width, height: height};
28884 this.syncBodyHeight();
28885 if(this.fixedcenter){
28888 if(this.isVisible()){
28889 this.constrainXY();
28890 this.adjustAssets();
28892 this.fireEvent("resize", this, width, height);
28898 * Resizes the dialog to fit the specified content size.
28899 * @param {Number} width
28900 * @param {Number} height
28901 * @return {Roo.BasicDialog} this
28903 setContentSize : function(w, h){
28904 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28905 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28906 //if(!this.el.isBorderBox()){
28907 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28908 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28911 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28912 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28914 this.resizeTo(w, h);
28919 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28920 * executed in response to a particular key being pressed while the dialog is active.
28921 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28922 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28923 * @param {Function} fn The function to call
28924 * @param {Object} scope (optional) The scope of the function
28925 * @return {Roo.BasicDialog} this
28927 addKeyListener : function(key, fn, scope){
28928 var keyCode, shift, ctrl, alt;
28929 if(typeof key == "object" && !(key instanceof Array)){
28930 keyCode = key["key"];
28931 shift = key["shift"];
28932 ctrl = key["ctrl"];
28937 var handler = function(dlg, e){
28938 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28939 var k = e.getKey();
28940 if(keyCode instanceof Array){
28941 for(var i = 0, len = keyCode.length; i < len; i++){
28942 if(keyCode[i] == k){
28943 fn.call(scope || window, dlg, k, e);
28949 fn.call(scope || window, dlg, k, e);
28954 this.on("keydown", handler);
28959 * Returns the TabPanel component (creates it if it doesn't exist).
28960 * Note: If you wish to simply check for the existence of tabs without creating them,
28961 * check for a null 'tabs' property.
28962 * @return {Roo.TabPanel} The tabs component
28964 getTabs : function(){
28966 this.el.addClass("x-dlg-auto-tabs");
28967 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28968 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28974 * Adds a button to the footer section of the dialog.
28975 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28976 * object or a valid Roo.DomHelper element config
28977 * @param {Function} handler The function called when the button is clicked
28978 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28979 * @return {Roo.Button} The new button
28981 addButton : function(config, handler, scope){
28982 var dh = Roo.DomHelper;
28984 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28986 if(!this.btnContainer){
28987 var tb = this.footer.createChild({
28989 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28990 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28992 this.btnContainer = tb.firstChild.firstChild.firstChild;
28997 minWidth: this.minButtonWidth,
29000 if(typeof config == "string"){
29001 bconfig.text = config;
29004 bconfig.dhconfig = config;
29006 Roo.apply(bconfig, config);
29010 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29011 bconfig.position = Math.max(0, bconfig.position);
29012 fc = this.btnContainer.childNodes[bconfig.position];
29015 var btn = new Roo.Button(
29017 this.btnContainer.insertBefore(document.createElement("td"),fc)
29018 : this.btnContainer.appendChild(document.createElement("td")),
29019 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29022 this.syncBodyHeight();
29025 * Array of all the buttons that have been added to this dialog via addButton
29030 this.buttons.push(btn);
29035 * Sets the default button to be focused when the dialog is displayed.
29036 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29037 * @return {Roo.BasicDialog} this
29039 setDefaultButton : function(btn){
29040 this.defaultButton = btn;
29045 getHeaderFooterHeight : function(safe){
29048 height += this.header.getHeight();
29051 var fm = this.footer.getMargins();
29052 height += (this.footer.getHeight()+fm.top+fm.bottom);
29054 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29055 height += this.centerBg.getPadding("tb");
29060 syncBodyHeight : function(){
29061 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29062 var height = this.size.height - this.getHeaderFooterHeight(false);
29063 bd.setHeight(height-bd.getMargins("tb"));
29064 var hh = this.header.getHeight();
29065 var h = this.size.height-hh;
29067 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29068 bw.setHeight(h-cb.getPadding("tb"));
29069 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29070 bd.setWidth(bw.getWidth(true));
29072 this.tabs.syncHeight();
29074 this.tabs.el.repaint();
29080 * Restores the previous state of the dialog if Roo.state is configured.
29081 * @return {Roo.BasicDialog} this
29083 restoreState : function(){
29084 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29085 if(box && box.width){
29086 this.xy = [box.x, box.y];
29087 this.resizeTo(box.width, box.height);
29093 beforeShow : function(){
29095 if(this.fixedcenter){
29096 this.xy = this.el.getCenterXY(true);
29099 Roo.get(document.body).addClass("x-body-masked");
29100 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29103 this.constrainXY();
29107 animShow : function(){
29108 var b = Roo.get(this.animateTarget).getBox();
29109 this.proxy.setSize(b.width, b.height);
29110 this.proxy.setLocation(b.x, b.y);
29112 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29113 true, .35, this.showEl.createDelegate(this));
29117 * Shows the dialog.
29118 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29119 * @return {Roo.BasicDialog} this
29121 show : function(animateTarget){
29122 if (this.fireEvent("beforeshow", this) === false){
29125 if(this.syncHeightBeforeShow){
29126 this.syncBodyHeight();
29127 }else if(this.firstShow){
29128 this.firstShow = false;
29129 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29131 this.animateTarget = animateTarget || this.animateTarget;
29132 if(!this.el.isVisible()){
29134 if(this.animateTarget && Roo.get(this.animateTarget)){
29144 showEl : function(){
29146 this.el.setXY(this.xy);
29148 this.adjustAssets(true);
29151 // IE peekaboo bug - fix found by Dave Fenwick
29155 this.fireEvent("show", this);
29159 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29160 * dialog itself will receive focus.
29162 focus : function(){
29163 if(this.defaultButton){
29164 this.defaultButton.focus();
29166 this.focusEl.focus();
29171 constrainXY : function(){
29172 if(this.constraintoviewport !== false){
29173 if(!this.viewSize){
29174 if(this.container){
29175 var s = this.container.getSize();
29176 this.viewSize = [s.width, s.height];
29178 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29181 var s = Roo.get(this.container||document).getScroll();
29183 var x = this.xy[0], y = this.xy[1];
29184 var w = this.size.width, h = this.size.height;
29185 var vw = this.viewSize[0], vh = this.viewSize[1];
29186 // only move it if it needs it
29188 // first validate right/bottom
29189 if(x + w > vw+s.left){
29193 if(y + h > vh+s.top){
29197 // then make sure top/left isn't negative
29209 if(this.isVisible()){
29210 this.el.setLocation(x, y);
29211 this.adjustAssets();
29218 onDrag : function(){
29219 if(!this.proxyDrag){
29220 this.xy = this.el.getXY();
29221 this.adjustAssets();
29226 adjustAssets : function(doShow){
29227 var x = this.xy[0], y = this.xy[1];
29228 var w = this.size.width, h = this.size.height;
29229 if(doShow === true){
29231 this.shadow.show(this.el);
29237 if(this.shadow && this.shadow.isVisible()){
29238 this.shadow.show(this.el);
29240 if(this.shim && this.shim.isVisible()){
29241 this.shim.setBounds(x, y, w, h);
29246 adjustViewport : function(w, h){
29248 w = Roo.lib.Dom.getViewWidth();
29249 h = Roo.lib.Dom.getViewHeight();
29252 this.viewSize = [w, h];
29253 if(this.modal && this.mask.isVisible()){
29254 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29255 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29257 if(this.isVisible()){
29258 this.constrainXY();
29263 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29264 * shadow, proxy, mask, etc.) Also removes all event listeners.
29265 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29267 destroy : function(removeEl){
29268 if(this.isVisible()){
29269 this.animateTarget = null;
29272 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29274 this.tabs.destroy(removeEl);
29287 for(var i = 0, len = this.buttons.length; i < len; i++){
29288 this.buttons[i].destroy();
29291 this.el.removeAllListeners();
29292 if(removeEl === true){
29293 this.el.update("");
29296 Roo.DialogManager.unregister(this);
29300 startMove : function(){
29301 if(this.proxyDrag){
29304 if(this.constraintoviewport !== false){
29305 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29310 endMove : function(){
29311 if(!this.proxyDrag){
29312 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29314 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29317 this.refreshSize();
29318 this.adjustAssets();
29320 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29324 * Brings this dialog to the front of any other visible dialogs
29325 * @return {Roo.BasicDialog} this
29327 toFront : function(){
29328 Roo.DialogManager.bringToFront(this);
29333 * Sends this dialog to the back (under) of any other visible dialogs
29334 * @return {Roo.BasicDialog} this
29336 toBack : function(){
29337 Roo.DialogManager.sendToBack(this);
29342 * Centers this dialog in the viewport
29343 * @return {Roo.BasicDialog} this
29345 center : function(){
29346 var xy = this.el.getCenterXY(true);
29347 this.moveTo(xy[0], xy[1]);
29352 * Moves the dialog's top-left corner to the specified point
29353 * @param {Number} x
29354 * @param {Number} y
29355 * @return {Roo.BasicDialog} this
29357 moveTo : function(x, y){
29359 if(this.isVisible()){
29360 this.el.setXY(this.xy);
29361 this.adjustAssets();
29367 * Aligns the dialog to the specified element
29368 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29369 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29370 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29371 * @return {Roo.BasicDialog} this
29373 alignTo : function(element, position, offsets){
29374 this.xy = this.el.getAlignToXY(element, position, offsets);
29375 if(this.isVisible()){
29376 this.el.setXY(this.xy);
29377 this.adjustAssets();
29383 * Anchors an element to another element and realigns it when the window is resized.
29384 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29385 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29386 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29387 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29388 * is a number, it is used as the buffer delay (defaults to 50ms).
29389 * @return {Roo.BasicDialog} this
29391 anchorTo : function(el, alignment, offsets, monitorScroll){
29392 var action = function(){
29393 this.alignTo(el, alignment, offsets);
29395 Roo.EventManager.onWindowResize(action, this);
29396 var tm = typeof monitorScroll;
29397 if(tm != 'undefined'){
29398 Roo.EventManager.on(window, 'scroll', action, this,
29399 {buffer: tm == 'number' ? monitorScroll : 50});
29406 * Returns true if the dialog is visible
29407 * @return {Boolean}
29409 isVisible : function(){
29410 return this.el.isVisible();
29414 animHide : function(callback){
29415 var b = Roo.get(this.animateTarget).getBox();
29417 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29419 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29420 this.hideEl.createDelegate(this, [callback]));
29424 * Hides the dialog.
29425 * @param {Function} callback (optional) Function to call when the dialog is hidden
29426 * @return {Roo.BasicDialog} this
29428 hide : function(callback){
29429 if (this.fireEvent("beforehide", this) === false){
29433 this.shadow.hide();
29438 // sometimes animateTarget seems to get set.. causing problems...
29439 // this just double checks..
29440 if(this.animateTarget && Roo.get(this.animateTarget)) {
29441 this.animHide(callback);
29444 this.hideEl(callback);
29450 hideEl : function(callback){
29454 Roo.get(document.body).removeClass("x-body-masked");
29456 this.fireEvent("hide", this);
29457 if(typeof callback == "function"){
29463 hideAction : function(){
29464 this.setLeft("-10000px");
29465 this.setTop("-10000px");
29466 this.setStyle("visibility", "hidden");
29470 refreshSize : function(){
29471 this.size = this.el.getSize();
29472 this.xy = this.el.getXY();
29473 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29477 // z-index is managed by the DialogManager and may be overwritten at any time
29478 setZIndex : function(index){
29480 this.mask.setStyle("z-index", index);
29483 this.shim.setStyle("z-index", ++index);
29486 this.shadow.setZIndex(++index);
29488 this.el.setStyle("z-index", ++index);
29490 this.proxy.setStyle("z-index", ++index);
29493 this.resizer.proxy.setStyle("z-index", ++index);
29496 this.lastZIndex = index;
29500 * Returns the element for this dialog
29501 * @return {Roo.Element} The underlying dialog Element
29503 getEl : function(){
29509 * @class Roo.DialogManager
29510 * Provides global access to BasicDialogs that have been created and
29511 * support for z-indexing (layering) multiple open dialogs.
29513 Roo.DialogManager = function(){
29515 var accessList = [];
29519 var sortDialogs = function(d1, d2){
29520 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29524 var orderDialogs = function(){
29525 accessList.sort(sortDialogs);
29526 var seed = Roo.DialogManager.zseed;
29527 for(var i = 0, len = accessList.length; i < len; i++){
29528 var dlg = accessList[i];
29530 dlg.setZIndex(seed + (i*10));
29537 * The starting z-index for BasicDialogs (defaults to 9000)
29538 * @type Number The z-index value
29543 register : function(dlg){
29544 list[dlg.id] = dlg;
29545 accessList.push(dlg);
29549 unregister : function(dlg){
29550 delete list[dlg.id];
29553 if(!accessList.indexOf){
29554 for( i = 0, len = accessList.length; i < len; i++){
29555 if(accessList[i] == dlg){
29556 accessList.splice(i, 1);
29561 i = accessList.indexOf(dlg);
29563 accessList.splice(i, 1);
29569 * Gets a registered dialog by id
29570 * @param {String/Object} id The id of the dialog or a dialog
29571 * @return {Roo.BasicDialog} this
29573 get : function(id){
29574 return typeof id == "object" ? id : list[id];
29578 * Brings the specified dialog to the front
29579 * @param {String/Object} dlg The id of the dialog or a dialog
29580 * @return {Roo.BasicDialog} this
29582 bringToFront : function(dlg){
29583 dlg = this.get(dlg);
29586 dlg._lastAccess = new Date().getTime();
29593 * Sends the specified dialog to the back
29594 * @param {String/Object} dlg The id of the dialog or a dialog
29595 * @return {Roo.BasicDialog} this
29597 sendToBack : function(dlg){
29598 dlg = this.get(dlg);
29599 dlg._lastAccess = -(new Date().getTime());
29605 * Hides all dialogs
29607 hideAll : function(){
29608 for(var id in list){
29609 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29618 * @class Roo.LayoutDialog
29619 * @extends Roo.BasicDialog
29620 * Dialog which provides adjustments for working with a layout in a Dialog.
29621 * Add your necessary layout config options to the dialog's config.<br>
29622 * Example usage (including a nested layout):
29625 dialog = new Roo.LayoutDialog("download-dlg", {
29634 // layout config merges with the dialog config
29636 tabPosition: "top",
29637 alwaysShowTabs: true
29640 dialog.addKeyListener(27, dialog.hide, dialog);
29641 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29642 dialog.addButton("Build It!", this.getDownload, this);
29644 // we can even add nested layouts
29645 var innerLayout = new Roo.BorderLayout("dl-inner", {
29655 innerLayout.beginUpdate();
29656 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29657 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29658 innerLayout.endUpdate(true);
29660 var layout = dialog.getLayout();
29661 layout.beginUpdate();
29662 layout.add("center", new Roo.ContentPanel("standard-panel",
29663 {title: "Download the Source", fitToFrame:true}));
29664 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29665 {title: "Build your own roo.js"}));
29666 layout.getRegion("center").showPanel(sp);
29667 layout.endUpdate();
29671 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29672 * @param {Object} config configuration options
29674 Roo.LayoutDialog = function(el, cfg){
29677 if (typeof(cfg) == 'undefined') {
29678 config = Roo.apply({}, el);
29679 // not sure why we use documentElement here.. - it should always be body.
29680 // IE7 borks horribly if we use documentElement.
29681 // webkit also does not like documentElement - it creates a body element...
29682 el = Roo.get( document.body || document.documentElement ).createChild();
29683 //config.autoCreate = true;
29687 config.autoTabs = false;
29688 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29689 this.body.setStyle({overflow:"hidden", position:"relative"});
29690 this.layout = new Roo.BorderLayout(this.body.dom, config);
29691 this.layout.monitorWindowResize = false;
29692 this.el.addClass("x-dlg-auto-layout");
29693 // fix case when center region overwrites center function
29694 this.center = Roo.BasicDialog.prototype.center;
29695 this.on("show", this.layout.layout, this.layout, true);
29696 if (config.items) {
29697 var xitems = config.items;
29698 delete config.items;
29699 Roo.each(xitems, this.addxtype, this);
29704 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29706 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29709 endUpdate : function(){
29710 this.layout.endUpdate();
29714 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29717 beginUpdate : function(){
29718 this.layout.beginUpdate();
29722 * Get the BorderLayout for this dialog
29723 * @return {Roo.BorderLayout}
29725 getLayout : function(){
29726 return this.layout;
29729 showEl : function(){
29730 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29732 this.layout.layout();
29737 // Use the syncHeightBeforeShow config option to control this automatically
29738 syncBodyHeight : function(){
29739 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29740 if(this.layout){this.layout.layout();}
29744 * Add an xtype element (actually adds to the layout.)
29745 * @return {Object} xdata xtype object data.
29748 addxtype : function(c) {
29749 return this.layout.addxtype(c);
29753 * Ext JS Library 1.1.1
29754 * Copyright(c) 2006-2007, Ext JS, LLC.
29756 * Originally Released Under LGPL - original licence link has changed is not relivant.
29759 * <script type="text/javascript">
29763 * @class Roo.MessageBox
29764 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29768 Roo.Msg.alert('Status', 'Changes saved successfully.');
29770 // Prompt for user data:
29771 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29773 // process text value...
29777 // Show a dialog using config options:
29779 title:'Save Changes?',
29780 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29781 buttons: Roo.Msg.YESNOCANCEL,
29788 Roo.MessageBox = function(){
29789 var dlg, opt, mask, waitTimer;
29790 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29791 var buttons, activeTextEl, bwidth;
29794 var handleButton = function(button){
29796 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29800 var handleHide = function(){
29801 if(opt && opt.cls){
29802 dlg.el.removeClass(opt.cls);
29805 Roo.TaskMgr.stop(waitTimer);
29811 var updateButtons = function(b){
29814 buttons["ok"].hide();
29815 buttons["cancel"].hide();
29816 buttons["yes"].hide();
29817 buttons["no"].hide();
29818 dlg.footer.dom.style.display = 'none';
29821 dlg.footer.dom.style.display = '';
29822 for(var k in buttons){
29823 if(typeof buttons[k] != "function"){
29826 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29827 width += buttons[k].el.getWidth()+15;
29837 var handleEsc = function(d, k, e){
29838 if(opt && opt.closable !== false){
29848 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29849 * @return {Roo.BasicDialog} The BasicDialog element
29851 getDialog : function(){
29853 dlg = new Roo.BasicDialog("x-msg-box", {
29858 constraintoviewport:false,
29860 collapsible : false,
29863 width:400, height:100,
29864 buttonAlign:"center",
29865 closeClick : function(){
29866 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29867 handleButton("no");
29869 handleButton("cancel");
29873 dlg.on("hide", handleHide);
29875 dlg.addKeyListener(27, handleEsc);
29877 var bt = this.buttonText;
29878 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29879 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29880 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29881 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29882 bodyEl = dlg.body.createChild({
29884 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>'
29886 msgEl = bodyEl.dom.firstChild;
29887 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29888 textboxEl.enableDisplayMode();
29889 textboxEl.addKeyListener([10,13], function(){
29890 if(dlg.isVisible() && opt && opt.buttons){
29891 if(opt.buttons.ok){
29892 handleButton("ok");
29893 }else if(opt.buttons.yes){
29894 handleButton("yes");
29898 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29899 textareaEl.enableDisplayMode();
29900 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29901 progressEl.enableDisplayMode();
29902 var pf = progressEl.dom.firstChild;
29904 pp = Roo.get(pf.firstChild);
29905 pp.setHeight(pf.offsetHeight);
29913 * Updates the message box body text
29914 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29915 * the XHTML-compliant non-breaking space character '&#160;')
29916 * @return {Roo.MessageBox} This message box
29918 updateText : function(text){
29919 if(!dlg.isVisible() && !opt.width){
29920 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29922 msgEl.innerHTML = text || ' ';
29923 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29924 Math.max(opt.minWidth || this.minWidth, bwidth));
29926 activeTextEl.setWidth(w);
29928 if(dlg.isVisible()){
29929 dlg.fixedcenter = false;
29931 dlg.setContentSize(w, bodyEl.getHeight());
29932 if(dlg.isVisible()){
29933 dlg.fixedcenter = true;
29939 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29940 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29941 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29942 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29943 * @return {Roo.MessageBox} This message box
29945 updateProgress : function(value, text){
29947 this.updateText(text);
29949 if (pp) { // weird bug on my firefox - for some reason this is not defined
29950 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29956 * Returns true if the message box is currently displayed
29957 * @return {Boolean} True if the message box is visible, else false
29959 isVisible : function(){
29960 return dlg && dlg.isVisible();
29964 * Hides the message box if it is displayed
29967 if(this.isVisible()){
29973 * Displays a new message box, or reinitializes an existing message box, based on the config options
29974 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29975 * The following config object properties are supported:
29977 Property Type Description
29978 ---------- --------------- ------------------------------------------------------------------------------------
29979 animEl String/Element An id or Element from which the message box should animate as it opens and
29980 closes (defaults to undefined)
29981 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29982 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29983 closable Boolean False to hide the top-right close button (defaults to true). Note that
29984 progress and wait dialogs will ignore this property and always hide the
29985 close button as they can only be closed programmatically.
29986 cls String A custom CSS class to apply to the message box element
29987 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29988 displayed (defaults to 75)
29989 fn Function A callback function to execute after closing the dialog. The arguments to the
29990 function will be btn (the name of the button that was clicked, if applicable,
29991 e.g. "ok"), and text (the value of the active text field, if applicable).
29992 Progress and wait dialogs will ignore this option since they do not respond to
29993 user actions and can only be closed programmatically, so any required function
29994 should be called by the same code after it closes the dialog.
29995 icon String A CSS class that provides a background image to be used as an icon for
29996 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29997 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29998 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29999 modal Boolean False to allow user interaction with the page while the message box is
30000 displayed (defaults to true)
30001 msg String A string that will replace the existing message box body text (defaults
30002 to the XHTML-compliant non-breaking space character ' ')
30003 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30004 progress Boolean True to display a progress bar (defaults to false)
30005 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30006 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30007 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30008 title String The title text
30009 value String The string value to set into the active textbox element if displayed
30010 wait Boolean True to display a progress bar (defaults to false)
30011 width Number The width of the dialog in pixels
30018 msg: 'Please enter your address:',
30020 buttons: Roo.MessageBox.OKCANCEL,
30023 animEl: 'addAddressBtn'
30026 * @param {Object} config Configuration options
30027 * @return {Roo.MessageBox} This message box
30029 show : function(options){
30030 if(this.isVisible()){
30033 var d = this.getDialog();
30035 d.setTitle(opt.title || " ");
30036 d.close.setDisplayed(opt.closable !== false);
30037 activeTextEl = textboxEl;
30038 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30043 textareaEl.setHeight(typeof opt.multiline == "number" ?
30044 opt.multiline : this.defaultTextHeight);
30045 activeTextEl = textareaEl;
30054 progressEl.setDisplayed(opt.progress === true);
30055 this.updateProgress(0);
30056 activeTextEl.dom.value = opt.value || "";
30058 dlg.setDefaultButton(activeTextEl);
30060 var bs = opt.buttons;
30063 db = buttons["ok"];
30064 }else if(bs && bs.yes){
30065 db = buttons["yes"];
30067 dlg.setDefaultButton(db);
30069 bwidth = updateButtons(opt.buttons);
30070 this.updateText(opt.msg);
30072 d.el.addClass(opt.cls);
30074 d.proxyDrag = opt.proxyDrag === true;
30075 d.modal = opt.modal !== false;
30076 d.mask = opt.modal !== false ? mask : false;
30077 if(!d.isVisible()){
30078 // force it to the end of the z-index stack so it gets a cursor in FF
30079 document.body.appendChild(dlg.el.dom);
30080 d.animateTarget = null;
30081 d.show(options.animEl);
30087 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30088 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30089 * and closing the message box when the process is complete.
30090 * @param {String} title The title bar text
30091 * @param {String} msg The message box body text
30092 * @return {Roo.MessageBox} This message box
30094 progress : function(title, msg){
30101 minWidth: this.minProgressWidth,
30108 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30109 * If a callback function is passed it will be called after the user clicks the button, and the
30110 * id of the button that was clicked will be passed as the only parameter to the callback
30111 * (could also be the top-right close button).
30112 * @param {String} title The title bar text
30113 * @param {String} msg The message box body text
30114 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30115 * @param {Object} scope (optional) The scope of the callback function
30116 * @return {Roo.MessageBox} This message box
30118 alert : function(title, msg, fn, scope){
30131 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30132 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30133 * You are responsible for closing the message box when the process is complete.
30134 * @param {String} msg The message box body text
30135 * @param {String} title (optional) The title bar text
30136 * @return {Roo.MessageBox} This message box
30138 wait : function(msg, title){
30149 waitTimer = Roo.TaskMgr.start({
30151 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30159 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30160 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30161 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30162 * @param {String} title The title bar text
30163 * @param {String} msg The message box body text
30164 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30165 * @param {Object} scope (optional) The scope of the callback function
30166 * @return {Roo.MessageBox} This message box
30168 confirm : function(title, msg, fn, scope){
30172 buttons: this.YESNO,
30181 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30182 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30183 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30184 * (could also be the top-right close button) and the text that was entered will be passed as the two
30185 * parameters to the callback.
30186 * @param {String} title The title bar text
30187 * @param {String} msg The message box body text
30188 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30189 * @param {Object} scope (optional) The scope of the callback function
30190 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30191 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30192 * @return {Roo.MessageBox} This message box
30194 prompt : function(title, msg, fn, scope, multiline){
30198 buttons: this.OKCANCEL,
30203 multiline: multiline,
30210 * Button config that displays a single OK button
30215 * Button config that displays Yes and No buttons
30218 YESNO : {yes:true, no:true},
30220 * Button config that displays OK and Cancel buttons
30223 OKCANCEL : {ok:true, cancel:true},
30225 * Button config that displays Yes, No and Cancel buttons
30228 YESNOCANCEL : {yes:true, no:true, cancel:true},
30231 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30234 defaultTextHeight : 75,
30236 * The maximum width in pixels of the message box (defaults to 600)
30241 * The minimum width in pixels of the message box (defaults to 100)
30246 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30247 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30250 minProgressWidth : 250,
30252 * An object containing the default button text strings that can be overriden for localized language support.
30253 * Supported properties are: ok, cancel, yes and no.
30254 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30267 * Shorthand for {@link Roo.MessageBox}
30269 Roo.Msg = Roo.MessageBox;/*
30271 * Ext JS Library 1.1.1
30272 * Copyright(c) 2006-2007, Ext JS, LLC.
30274 * Originally Released Under LGPL - original licence link has changed is not relivant.
30277 * <script type="text/javascript">
30280 * @class Roo.QuickTips
30281 * Provides attractive and customizable tooltips for any element.
30284 Roo.QuickTips = function(){
30285 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30286 var ce, bd, xy, dd;
30287 var visible = false, disabled = true, inited = false;
30288 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30290 var onOver = function(e){
30294 var t = e.getTarget();
30295 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30298 if(ce && t == ce.el){
30299 clearTimeout(hideProc);
30302 if(t && tagEls[t.id]){
30303 tagEls[t.id].el = t;
30304 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30307 var ttp, et = Roo.fly(t);
30308 var ns = cfg.namespace;
30309 if(tm.interceptTitles && t.title){
30312 t.removeAttribute("title");
30313 e.preventDefault();
30315 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30318 showProc = show.defer(tm.showDelay, tm, [{
30321 width: et.getAttributeNS(ns, cfg.width),
30322 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30323 title: et.getAttributeNS(ns, cfg.title),
30324 cls: et.getAttributeNS(ns, cfg.cls)
30329 var onOut = function(e){
30330 clearTimeout(showProc);
30331 var t = e.getTarget();
30332 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30333 hideProc = setTimeout(hide, tm.hideDelay);
30337 var onMove = function(e){
30343 if(tm.trackMouse && ce){
30348 var onDown = function(e){
30349 clearTimeout(showProc);
30350 clearTimeout(hideProc);
30352 if(tm.hideOnClick){
30355 tm.enable.defer(100, tm);
30360 var getPad = function(){
30361 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30364 var show = function(o){
30368 clearTimeout(dismissProc);
30370 if(removeCls){ // in case manually hidden
30371 el.removeClass(removeCls);
30375 el.addClass(ce.cls);
30376 removeCls = ce.cls;
30379 tipTitle.update(ce.title);
30382 tipTitle.update('');
30385 el.dom.style.width = tm.maxWidth+'px';
30386 //tipBody.dom.style.width = '';
30387 tipBodyText.update(o.text);
30388 var p = getPad(), w = ce.width;
30390 var td = tipBodyText.dom;
30391 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30392 if(aw > tm.maxWidth){
30394 }else if(aw < tm.minWidth){
30400 //tipBody.setWidth(w);
30401 el.setWidth(parseInt(w, 10) + p);
30402 if(ce.autoHide === false){
30403 close.setDisplayed(true);
30408 close.setDisplayed(false);
30414 el.avoidY = xy[1]-18;
30419 el.setStyle("visibility", "visible");
30420 el.fadeIn({callback: afterShow});
30426 var afterShow = function(){
30430 if(tm.autoDismiss && ce.autoHide !== false){
30431 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30436 var hide = function(noanim){
30437 clearTimeout(dismissProc);
30438 clearTimeout(hideProc);
30440 if(el.isVisible()){
30442 if(noanim !== true && tm.animate){
30443 el.fadeOut({callback: afterHide});
30450 var afterHide = function(){
30453 el.removeClass(removeCls);
30460 * @cfg {Number} minWidth
30461 * The minimum width of the quick tip (defaults to 40)
30465 * @cfg {Number} maxWidth
30466 * The maximum width of the quick tip (defaults to 300)
30470 * @cfg {Boolean} interceptTitles
30471 * True to automatically use the element's DOM title value if available (defaults to false)
30473 interceptTitles : false,
30475 * @cfg {Boolean} trackMouse
30476 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30478 trackMouse : false,
30480 * @cfg {Boolean} hideOnClick
30481 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30483 hideOnClick : true,
30485 * @cfg {Number} showDelay
30486 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30490 * @cfg {Number} hideDelay
30491 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30495 * @cfg {Boolean} autoHide
30496 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30497 * Used in conjunction with hideDelay.
30502 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30503 * (defaults to true). Used in conjunction with autoDismissDelay.
30505 autoDismiss : true,
30508 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30510 autoDismissDelay : 5000,
30512 * @cfg {Boolean} animate
30513 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30518 * @cfg {String} title
30519 * Title text to display (defaults to ''). This can be any valid HTML markup.
30523 * @cfg {String} text
30524 * Body text to display (defaults to ''). This can be any valid HTML markup.
30528 * @cfg {String} cls
30529 * A CSS class to apply to the base quick tip element (defaults to '').
30533 * @cfg {Number} width
30534 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30535 * minWidth or maxWidth.
30540 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30541 * or display QuickTips in a page.
30544 tm = Roo.QuickTips;
30545 cfg = tm.tagConfig;
30547 if(!Roo.isReady){ // allow calling of init() before onReady
30548 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30551 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30552 el.fxDefaults = {stopFx: true};
30553 // maximum custom styling
30554 //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>');
30555 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>');
30556 tipTitle = el.child('h3');
30557 tipTitle.enableDisplayMode("block");
30558 tipBody = el.child('div.x-tip-bd');
30559 tipBodyText = el.child('div.x-tip-bd-inner');
30560 //bdLeft = el.child('div.x-tip-bd-left');
30561 //bdRight = el.child('div.x-tip-bd-right');
30562 close = el.child('div.x-tip-close');
30563 close.enableDisplayMode("block");
30564 close.on("click", hide);
30565 var d = Roo.get(document);
30566 d.on("mousedown", onDown);
30567 d.on("mouseover", onOver);
30568 d.on("mouseout", onOut);
30569 d.on("mousemove", onMove);
30570 esc = d.addKeyListener(27, hide);
30573 dd = el.initDD("default", null, {
30574 onDrag : function(){
30578 dd.setHandleElId(tipTitle.id);
30587 * Configures a new quick tip instance and assigns it to a target element. The following config options
30590 Property Type Description
30591 ---------- --------------------- ------------------------------------------------------------------------
30592 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30594 * @param {Object} config The config object
30596 register : function(config){
30597 var cs = config instanceof Array ? config : arguments;
30598 for(var i = 0, len = cs.length; i < len; i++) {
30600 var target = c.target;
30602 if(target instanceof Array){
30603 for(var j = 0, jlen = target.length; j < jlen; j++){
30604 tagEls[target[j]] = c;
30607 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30614 * Removes this quick tip from its element and destroys it.
30615 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30617 unregister : function(el){
30618 delete tagEls[Roo.id(el)];
30622 * Enable this quick tip.
30624 enable : function(){
30625 if(inited && disabled){
30627 if(locks.length < 1){
30634 * Disable this quick tip.
30636 disable : function(){
30638 clearTimeout(showProc);
30639 clearTimeout(hideProc);
30640 clearTimeout(dismissProc);
30648 * Returns true if the quick tip is enabled, else false.
30650 isEnabled : function(){
30657 attribute : "qtip",
30667 // backwards compat
30668 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30670 * Ext JS Library 1.1.1
30671 * Copyright(c) 2006-2007, Ext JS, LLC.
30673 * Originally Released Under LGPL - original licence link has changed is not relivant.
30676 * <script type="text/javascript">
30681 * @class Roo.tree.TreePanel
30682 * @extends Roo.data.Tree
30684 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30685 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30686 * @cfg {Boolean} enableDD true to enable drag and drop
30687 * @cfg {Boolean} enableDrag true to enable just drag
30688 * @cfg {Boolean} enableDrop true to enable just drop
30689 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30690 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30691 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30692 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30693 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30694 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30695 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30696 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30697 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30698 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30699 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30700 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30701 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30702 * @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>
30703 * @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>
30706 * @param {String/HTMLElement/Element} el The container element
30707 * @param {Object} config
30709 Roo.tree.TreePanel = function(el, config){
30711 var loader = false;
30713 root = config.root;
30714 delete config.root;
30716 if (config.loader) {
30717 loader = config.loader;
30718 delete config.loader;
30721 Roo.apply(this, config);
30722 Roo.tree.TreePanel.superclass.constructor.call(this);
30723 this.el = Roo.get(el);
30724 this.el.addClass('x-tree');
30725 //console.log(root);
30727 this.setRootNode( Roo.factory(root, Roo.tree));
30730 this.loader = Roo.factory(loader, Roo.tree);
30733 * Read-only. The id of the container element becomes this TreePanel's id.
30735 this.id = this.el.id;
30738 * @event beforeload
30739 * Fires before a node is loaded, return false to cancel
30740 * @param {Node} node The node being loaded
30742 "beforeload" : true,
30745 * Fires when a node is loaded
30746 * @param {Node} node The node that was loaded
30750 * @event textchange
30751 * Fires when the text for a node is changed
30752 * @param {Node} node The node
30753 * @param {String} text The new text
30754 * @param {String} oldText The old text
30756 "textchange" : true,
30758 * @event beforeexpand
30759 * Fires before a node is expanded, return false to cancel.
30760 * @param {Node} node The node
30761 * @param {Boolean} deep
30762 * @param {Boolean} anim
30764 "beforeexpand" : true,
30766 * @event beforecollapse
30767 * Fires before a node is collapsed, return false to cancel.
30768 * @param {Node} node The node
30769 * @param {Boolean} deep
30770 * @param {Boolean} anim
30772 "beforecollapse" : true,
30775 * Fires when a node is expanded
30776 * @param {Node} node The node
30780 * @event disabledchange
30781 * Fires when the disabled status of a node changes
30782 * @param {Node} node The node
30783 * @param {Boolean} disabled
30785 "disabledchange" : true,
30788 * Fires when a node is collapsed
30789 * @param {Node} node The node
30793 * @event beforeclick
30794 * Fires before click processing on a node. Return false to cancel the default action.
30795 * @param {Node} node The node
30796 * @param {Roo.EventObject} e The event object
30798 "beforeclick":true,
30800 * @event checkchange
30801 * Fires when a node with a checkbox's checked property changes
30802 * @param {Node} this This node
30803 * @param {Boolean} checked
30805 "checkchange":true,
30808 * Fires when a node is clicked
30809 * @param {Node} node The node
30810 * @param {Roo.EventObject} e The event object
30815 * Fires when a node is double clicked
30816 * @param {Node} node The node
30817 * @param {Roo.EventObject} e The event object
30821 * @event contextmenu
30822 * Fires when a node is right clicked
30823 * @param {Node} node The node
30824 * @param {Roo.EventObject} e The event object
30826 "contextmenu":true,
30828 * @event beforechildrenrendered
30829 * Fires right before the child nodes for a node are rendered
30830 * @param {Node} node The node
30832 "beforechildrenrendered":true,
30835 * Fires when a node starts being dragged
30836 * @param {Roo.tree.TreePanel} this
30837 * @param {Roo.tree.TreeNode} node
30838 * @param {event} e The raw browser event
30840 "startdrag" : true,
30843 * Fires when a drag operation is complete
30844 * @param {Roo.tree.TreePanel} this
30845 * @param {Roo.tree.TreeNode} node
30846 * @param {event} e The raw browser event
30851 * Fires when a dragged node is dropped on a valid DD target
30852 * @param {Roo.tree.TreePanel} this
30853 * @param {Roo.tree.TreeNode} node
30854 * @param {DD} dd The dd it was dropped on
30855 * @param {event} e The raw browser event
30859 * @event beforenodedrop
30860 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30861 * passed to handlers has the following properties:<br />
30862 * <ul style="padding:5px;padding-left:16px;">
30863 * <li>tree - The TreePanel</li>
30864 * <li>target - The node being targeted for the drop</li>
30865 * <li>data - The drag data from the drag source</li>
30866 * <li>point - The point of the drop - append, above or below</li>
30867 * <li>source - The drag source</li>
30868 * <li>rawEvent - Raw mouse event</li>
30869 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30870 * to be inserted by setting them on this object.</li>
30871 * <li>cancel - Set this to true to cancel the drop.</li>
30873 * @param {Object} dropEvent
30875 "beforenodedrop" : true,
30878 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30879 * passed to handlers has the following properties:<br />
30880 * <ul style="padding:5px;padding-left:16px;">
30881 * <li>tree - The TreePanel</li>
30882 * <li>target - The node being targeted for the drop</li>
30883 * <li>data - The drag data from the drag source</li>
30884 * <li>point - The point of the drop - append, above or below</li>
30885 * <li>source - The drag source</li>
30886 * <li>rawEvent - Raw mouse event</li>
30887 * <li>dropNode - Dropped node(s).</li>
30889 * @param {Object} dropEvent
30893 * @event nodedragover
30894 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30895 * passed to handlers has the following properties:<br />
30896 * <ul style="padding:5px;padding-left:16px;">
30897 * <li>tree - The TreePanel</li>
30898 * <li>target - The node being targeted for the drop</li>
30899 * <li>data - The drag data from the drag source</li>
30900 * <li>point - The point of the drop - append, above or below</li>
30901 * <li>source - The drag source</li>
30902 * <li>rawEvent - Raw mouse event</li>
30903 * <li>dropNode - Drop node(s) provided by the source.</li>
30904 * <li>cancel - Set this to true to signal drop not allowed.</li>
30906 * @param {Object} dragOverEvent
30908 "nodedragover" : true
30911 if(this.singleExpand){
30912 this.on("beforeexpand", this.restrictExpand, this);
30915 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30916 rootVisible : true,
30917 animate: Roo.enableFx,
30920 hlDrop : Roo.enableFx,
30924 rendererTip: false,
30926 restrictExpand : function(node){
30927 var p = node.parentNode;
30929 if(p.expandedChild && p.expandedChild.parentNode == p){
30930 p.expandedChild.collapse();
30932 p.expandedChild = node;
30936 // private override
30937 setRootNode : function(node){
30938 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30939 if(!this.rootVisible){
30940 node.ui = new Roo.tree.RootTreeNodeUI(node);
30946 * Returns the container element for this TreePanel
30948 getEl : function(){
30953 * Returns the default TreeLoader for this TreePanel
30955 getLoader : function(){
30956 return this.loader;
30962 expandAll : function(){
30963 this.root.expand(true);
30967 * Collapse all nodes
30969 collapseAll : function(){
30970 this.root.collapse(true);
30974 * Returns the selection model used by this TreePanel
30976 getSelectionModel : function(){
30977 if(!this.selModel){
30978 this.selModel = new Roo.tree.DefaultSelectionModel();
30980 return this.selModel;
30984 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30985 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30986 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30989 getChecked : function(a, startNode){
30990 startNode = startNode || this.root;
30992 var f = function(){
30993 if(this.attributes.checked){
30994 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30997 startNode.cascade(f);
31002 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31003 * @param {String} path
31004 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31005 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31006 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31008 expandPath : function(path, attr, callback){
31009 attr = attr || "id";
31010 var keys = path.split(this.pathSeparator);
31011 var curNode = this.root;
31012 if(curNode.attributes[attr] != keys[1]){ // invalid root
31014 callback(false, null);
31019 var f = function(){
31020 if(++index == keys.length){
31022 callback(true, curNode);
31026 var c = curNode.findChild(attr, keys[index]);
31029 callback(false, curNode);
31034 c.expand(false, false, f);
31036 curNode.expand(false, false, f);
31040 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31041 * @param {String} path
31042 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31043 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31044 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31046 selectPath : function(path, attr, callback){
31047 attr = attr || "id";
31048 var keys = path.split(this.pathSeparator);
31049 var v = keys.pop();
31050 if(keys.length > 0){
31051 var f = function(success, node){
31052 if(success && node){
31053 var n = node.findChild(attr, v);
31059 }else if(callback){
31060 callback(false, n);
31064 callback(false, n);
31068 this.expandPath(keys.join(this.pathSeparator), attr, f);
31070 this.root.select();
31072 callback(true, this.root);
31077 getTreeEl : function(){
31082 * Trigger rendering of this TreePanel
31084 render : function(){
31085 if (this.innerCt) {
31086 return this; // stop it rendering more than once!!
31089 this.innerCt = this.el.createChild({tag:"ul",
31090 cls:"x-tree-root-ct " +
31091 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31093 if(this.containerScroll){
31094 Roo.dd.ScrollManager.register(this.el);
31096 if((this.enableDD || this.enableDrop) && !this.dropZone){
31098 * The dropZone used by this tree if drop is enabled
31099 * @type Roo.tree.TreeDropZone
31101 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31102 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31105 if((this.enableDD || this.enableDrag) && !this.dragZone){
31107 * The dragZone used by this tree if drag is enabled
31108 * @type Roo.tree.TreeDragZone
31110 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31111 ddGroup: this.ddGroup || "TreeDD",
31112 scroll: this.ddScroll
31115 this.getSelectionModel().init(this);
31117 console.log("ROOT not set in tree");
31120 this.root.render();
31121 if(!this.rootVisible){
31122 this.root.renderChildren();
31128 * Ext JS Library 1.1.1
31129 * Copyright(c) 2006-2007, Ext JS, LLC.
31131 * Originally Released Under LGPL - original licence link has changed is not relivant.
31134 * <script type="text/javascript">
31139 * @class Roo.tree.DefaultSelectionModel
31140 * @extends Roo.util.Observable
31141 * The default single selection for a TreePanel.
31143 Roo.tree.DefaultSelectionModel = function(){
31144 this.selNode = null;
31148 * @event selectionchange
31149 * Fires when the selected node changes
31150 * @param {DefaultSelectionModel} this
31151 * @param {TreeNode} node the new selection
31153 "selectionchange" : true,
31156 * @event beforeselect
31157 * Fires before the selected node changes, return false to cancel the change
31158 * @param {DefaultSelectionModel} this
31159 * @param {TreeNode} node the new selection
31160 * @param {TreeNode} node the old selection
31162 "beforeselect" : true
31166 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31167 init : function(tree){
31169 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31170 tree.on("click", this.onNodeClick, this);
31173 onNodeClick : function(node, e){
31174 if (e.ctrlKey && this.selNode == node) {
31175 this.unselect(node);
31183 * @param {TreeNode} node The node to select
31184 * @return {TreeNode} The selected node
31186 select : function(node){
31187 var last = this.selNode;
31188 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31190 last.ui.onSelectedChange(false);
31192 this.selNode = node;
31193 node.ui.onSelectedChange(true);
31194 this.fireEvent("selectionchange", this, node, last);
31201 * @param {TreeNode} node The node to unselect
31203 unselect : function(node){
31204 if(this.selNode == node){
31205 this.clearSelections();
31210 * Clear all selections
31212 clearSelections : function(){
31213 var n = this.selNode;
31215 n.ui.onSelectedChange(false);
31216 this.selNode = null;
31217 this.fireEvent("selectionchange", this, null);
31223 * Get the selected node
31224 * @return {TreeNode} The selected node
31226 getSelectedNode : function(){
31227 return this.selNode;
31231 * Returns true if the node is selected
31232 * @param {TreeNode} node The node to check
31233 * @return {Boolean}
31235 isSelected : function(node){
31236 return this.selNode == node;
31240 * Selects the node above the selected node in the tree, intelligently walking the nodes
31241 * @return TreeNode The new selection
31243 selectPrevious : function(){
31244 var s = this.selNode || this.lastSelNode;
31248 var ps = s.previousSibling;
31250 if(!ps.isExpanded() || ps.childNodes.length < 1){
31251 return this.select(ps);
31253 var lc = ps.lastChild;
31254 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31257 return this.select(lc);
31259 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31260 return this.select(s.parentNode);
31266 * Selects the node above the selected node in the tree, intelligently walking the nodes
31267 * @return TreeNode The new selection
31269 selectNext : function(){
31270 var s = this.selNode || this.lastSelNode;
31274 if(s.firstChild && s.isExpanded()){
31275 return this.select(s.firstChild);
31276 }else if(s.nextSibling){
31277 return this.select(s.nextSibling);
31278 }else if(s.parentNode){
31280 s.parentNode.bubble(function(){
31281 if(this.nextSibling){
31282 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31291 onKeyDown : function(e){
31292 var s = this.selNode || this.lastSelNode;
31293 // undesirable, but required
31298 var k = e.getKey();
31306 this.selectPrevious();
31309 e.preventDefault();
31310 if(s.hasChildNodes()){
31311 if(!s.isExpanded()){
31313 }else if(s.firstChild){
31314 this.select(s.firstChild, e);
31319 e.preventDefault();
31320 if(s.hasChildNodes() && s.isExpanded()){
31322 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31323 this.select(s.parentNode, e);
31331 * @class Roo.tree.MultiSelectionModel
31332 * @extends Roo.util.Observable
31333 * Multi selection for a TreePanel.
31335 Roo.tree.MultiSelectionModel = function(){
31336 this.selNodes = [];
31340 * @event selectionchange
31341 * Fires when the selected nodes change
31342 * @param {MultiSelectionModel} this
31343 * @param {Array} nodes Array of the selected nodes
31345 "selectionchange" : true
31349 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31350 init : function(tree){
31352 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31353 tree.on("click", this.onNodeClick, this);
31356 onNodeClick : function(node, e){
31357 this.select(node, e, e.ctrlKey);
31362 * @param {TreeNode} node The node to select
31363 * @param {EventObject} e (optional) An event associated with the selection
31364 * @param {Boolean} keepExisting True to retain existing selections
31365 * @return {TreeNode} The selected node
31367 select : function(node, e, keepExisting){
31368 if(keepExisting !== true){
31369 this.clearSelections(true);
31371 if(this.isSelected(node)){
31372 this.lastSelNode = node;
31375 this.selNodes.push(node);
31376 this.selMap[node.id] = node;
31377 this.lastSelNode = node;
31378 node.ui.onSelectedChange(true);
31379 this.fireEvent("selectionchange", this, this.selNodes);
31385 * @param {TreeNode} node The node to unselect
31387 unselect : function(node){
31388 if(this.selMap[node.id]){
31389 node.ui.onSelectedChange(false);
31390 var sn = this.selNodes;
31393 index = sn.indexOf(node);
31395 for(var i = 0, len = sn.length; i < len; i++){
31403 this.selNodes.splice(index, 1);
31405 delete this.selMap[node.id];
31406 this.fireEvent("selectionchange", this, this.selNodes);
31411 * Clear all selections
31413 clearSelections : function(suppressEvent){
31414 var sn = this.selNodes;
31416 for(var i = 0, len = sn.length; i < len; i++){
31417 sn[i].ui.onSelectedChange(false);
31419 this.selNodes = [];
31421 if(suppressEvent !== true){
31422 this.fireEvent("selectionchange", this, this.selNodes);
31428 * Returns true if the node is selected
31429 * @param {TreeNode} node The node to check
31430 * @return {Boolean}
31432 isSelected : function(node){
31433 return this.selMap[node.id] ? true : false;
31437 * Returns an array of the selected nodes
31440 getSelectedNodes : function(){
31441 return this.selNodes;
31444 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31446 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31448 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31451 * Ext JS Library 1.1.1
31452 * Copyright(c) 2006-2007, Ext JS, LLC.
31454 * Originally Released Under LGPL - original licence link has changed is not relivant.
31457 * <script type="text/javascript">
31461 * @class Roo.tree.TreeNode
31462 * @extends Roo.data.Node
31463 * @cfg {String} text The text for this node
31464 * @cfg {Boolean} expanded true to start the node expanded
31465 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31466 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31467 * @cfg {Boolean} disabled true to start the node disabled
31468 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31469 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31470 * @cfg {String} cls A css class to be added to the node
31471 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31472 * @cfg {String} href URL of the link used for the node (defaults to #)
31473 * @cfg {String} hrefTarget target frame for the link
31474 * @cfg {String} qtip An Ext QuickTip for the node
31475 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31476 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31477 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31478 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31479 * (defaults to undefined with no checkbox rendered)
31481 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31483 Roo.tree.TreeNode = function(attributes){
31484 attributes = attributes || {};
31485 if(typeof attributes == "string"){
31486 attributes = {text: attributes};
31488 this.childrenRendered = false;
31489 this.rendered = false;
31490 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31491 this.expanded = attributes.expanded === true;
31492 this.isTarget = attributes.isTarget !== false;
31493 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31494 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31497 * Read-only. The text for this node. To change it use setText().
31500 this.text = attributes.text;
31502 * True if this node is disabled.
31505 this.disabled = attributes.disabled === true;
31509 * @event textchange
31510 * Fires when the text for this node is changed
31511 * @param {Node} this This node
31512 * @param {String} text The new text
31513 * @param {String} oldText The old text
31515 "textchange" : true,
31517 * @event beforeexpand
31518 * Fires before this node is expanded, return false to cancel.
31519 * @param {Node} this This node
31520 * @param {Boolean} deep
31521 * @param {Boolean} anim
31523 "beforeexpand" : true,
31525 * @event beforecollapse
31526 * Fires before this node is collapsed, return false to cancel.
31527 * @param {Node} this This node
31528 * @param {Boolean} deep
31529 * @param {Boolean} anim
31531 "beforecollapse" : true,
31534 * Fires when this node is expanded
31535 * @param {Node} this This node
31539 * @event disabledchange
31540 * Fires when the disabled status of this node changes
31541 * @param {Node} this This node
31542 * @param {Boolean} disabled
31544 "disabledchange" : true,
31547 * Fires when this node is collapsed
31548 * @param {Node} this This node
31552 * @event beforeclick
31553 * Fires before click processing. Return false to cancel the default action.
31554 * @param {Node} this This node
31555 * @param {Roo.EventObject} e The event object
31557 "beforeclick":true,
31559 * @event checkchange
31560 * Fires when a node with a checkbox's checked property changes
31561 * @param {Node} this This node
31562 * @param {Boolean} checked
31564 "checkchange":true,
31567 * Fires when this node is clicked
31568 * @param {Node} this This node
31569 * @param {Roo.EventObject} e The event object
31574 * Fires when this node is double clicked
31575 * @param {Node} this This node
31576 * @param {Roo.EventObject} e The event object
31580 * @event contextmenu
31581 * Fires when this node is right clicked
31582 * @param {Node} this This node
31583 * @param {Roo.EventObject} e The event object
31585 "contextmenu":true,
31587 * @event beforechildrenrendered
31588 * Fires right before the child nodes for this node are rendered
31589 * @param {Node} this This node
31591 "beforechildrenrendered":true
31594 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31597 * Read-only. The UI for this node
31600 this.ui = new uiClass(this);
31602 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31603 preventHScroll: true,
31605 * Returns true if this node is expanded
31606 * @return {Boolean}
31608 isExpanded : function(){
31609 return this.expanded;
31613 * Returns the UI object for this node
31614 * @return {TreeNodeUI}
31616 getUI : function(){
31620 // private override
31621 setFirstChild : function(node){
31622 var of = this.firstChild;
31623 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31624 if(this.childrenRendered && of && node != of){
31625 of.renderIndent(true, true);
31628 this.renderIndent(true, true);
31632 // private override
31633 setLastChild : function(node){
31634 var ol = this.lastChild;
31635 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31636 if(this.childrenRendered && ol && node != ol){
31637 ol.renderIndent(true, true);
31640 this.renderIndent(true, true);
31644 // these methods are overridden to provide lazy rendering support
31645 // private override
31646 appendChild : function(){
31647 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31648 if(node && this.childrenRendered){
31651 this.ui.updateExpandIcon();
31655 // private override
31656 removeChild : function(node){
31657 this.ownerTree.getSelectionModel().unselect(node);
31658 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31659 // if it's been rendered remove dom node
31660 if(this.childrenRendered){
31663 if(this.childNodes.length < 1){
31664 this.collapse(false, false);
31666 this.ui.updateExpandIcon();
31668 if(!this.firstChild) {
31669 this.childrenRendered = false;
31674 // private override
31675 insertBefore : function(node, refNode){
31676 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31677 if(newNode && refNode && this.childrenRendered){
31680 this.ui.updateExpandIcon();
31685 * Sets the text for this node
31686 * @param {String} text
31688 setText : function(text){
31689 var oldText = this.text;
31691 this.attributes.text = text;
31692 if(this.rendered){ // event without subscribing
31693 this.ui.onTextChange(this, text, oldText);
31695 this.fireEvent("textchange", this, text, oldText);
31699 * Triggers selection of this node
31701 select : function(){
31702 this.getOwnerTree().getSelectionModel().select(this);
31706 * Triggers deselection of this node
31708 unselect : function(){
31709 this.getOwnerTree().getSelectionModel().unselect(this);
31713 * Returns true if this node is selected
31714 * @return {Boolean}
31716 isSelected : function(){
31717 return this.getOwnerTree().getSelectionModel().isSelected(this);
31721 * Expand this node.
31722 * @param {Boolean} deep (optional) True to expand all children as well
31723 * @param {Boolean} anim (optional) false to cancel the default animation
31724 * @param {Function} callback (optional) A callback to be called when
31725 * expanding this node completes (does not wait for deep expand to complete).
31726 * Called with 1 parameter, this node.
31728 expand : function(deep, anim, callback){
31729 if(!this.expanded){
31730 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31733 if(!this.childrenRendered){
31734 this.renderChildren();
31736 this.expanded = true;
31737 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31738 this.ui.animExpand(function(){
31739 this.fireEvent("expand", this);
31740 if(typeof callback == "function"){
31744 this.expandChildNodes(true);
31746 }.createDelegate(this));
31750 this.fireEvent("expand", this);
31751 if(typeof callback == "function"){
31756 if(typeof callback == "function"){
31761 this.expandChildNodes(true);
31765 isHiddenRoot : function(){
31766 return this.isRoot && !this.getOwnerTree().rootVisible;
31770 * Collapse this node.
31771 * @param {Boolean} deep (optional) True to collapse all children as well
31772 * @param {Boolean} anim (optional) false to cancel the default animation
31774 collapse : function(deep, anim){
31775 if(this.expanded && !this.isHiddenRoot()){
31776 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31779 this.expanded = false;
31780 if((this.getOwnerTree().animate && anim !== false) || anim){
31781 this.ui.animCollapse(function(){
31782 this.fireEvent("collapse", this);
31784 this.collapseChildNodes(true);
31786 }.createDelegate(this));
31789 this.ui.collapse();
31790 this.fireEvent("collapse", this);
31794 var cs = this.childNodes;
31795 for(var i = 0, len = cs.length; i < len; i++) {
31796 cs[i].collapse(true, false);
31802 delayedExpand : function(delay){
31803 if(!this.expandProcId){
31804 this.expandProcId = this.expand.defer(delay, this);
31809 cancelExpand : function(){
31810 if(this.expandProcId){
31811 clearTimeout(this.expandProcId);
31813 this.expandProcId = false;
31817 * Toggles expanded/collapsed state of the node
31819 toggle : function(){
31828 * Ensures all parent nodes are expanded
31830 ensureVisible : function(callback){
31831 var tree = this.getOwnerTree();
31832 tree.expandPath(this.parentNode.getPath(), false, function(){
31833 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31834 Roo.callback(callback);
31835 }.createDelegate(this));
31839 * Expand all child nodes
31840 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31842 expandChildNodes : function(deep){
31843 var cs = this.childNodes;
31844 for(var i = 0, len = cs.length; i < len; i++) {
31845 cs[i].expand(deep);
31850 * Collapse all child nodes
31851 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31853 collapseChildNodes : function(deep){
31854 var cs = this.childNodes;
31855 for(var i = 0, len = cs.length; i < len; i++) {
31856 cs[i].collapse(deep);
31861 * Disables this node
31863 disable : function(){
31864 this.disabled = true;
31866 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31867 this.ui.onDisableChange(this, true);
31869 this.fireEvent("disabledchange", this, true);
31873 * Enables this node
31875 enable : function(){
31876 this.disabled = false;
31877 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31878 this.ui.onDisableChange(this, false);
31880 this.fireEvent("disabledchange", this, false);
31884 renderChildren : function(suppressEvent){
31885 if(suppressEvent !== false){
31886 this.fireEvent("beforechildrenrendered", this);
31888 var cs = this.childNodes;
31889 for(var i = 0, len = cs.length; i < len; i++){
31890 cs[i].render(true);
31892 this.childrenRendered = true;
31896 sort : function(fn, scope){
31897 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31898 if(this.childrenRendered){
31899 var cs = this.childNodes;
31900 for(var i = 0, len = cs.length; i < len; i++){
31901 cs[i].render(true);
31907 render : function(bulkRender){
31908 this.ui.render(bulkRender);
31909 if(!this.rendered){
31910 this.rendered = true;
31912 this.expanded = false;
31913 this.expand(false, false);
31919 renderIndent : function(deep, refresh){
31921 this.ui.childIndent = null;
31923 this.ui.renderIndent();
31924 if(deep === true && this.childrenRendered){
31925 var cs = this.childNodes;
31926 for(var i = 0, len = cs.length; i < len; i++){
31927 cs[i].renderIndent(true, refresh);
31933 * Ext JS Library 1.1.1
31934 * Copyright(c) 2006-2007, Ext JS, LLC.
31936 * Originally Released Under LGPL - original licence link has changed is not relivant.
31939 * <script type="text/javascript">
31943 * @class Roo.tree.AsyncTreeNode
31944 * @extends Roo.tree.TreeNode
31945 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31947 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31949 Roo.tree.AsyncTreeNode = function(config){
31950 this.loaded = false;
31951 this.loading = false;
31952 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31954 * @event beforeload
31955 * Fires before this node is loaded, return false to cancel
31956 * @param {Node} this This node
31958 this.addEvents({'beforeload':true, 'load': true});
31961 * Fires when this node is loaded
31962 * @param {Node} this This node
31965 * The loader used by this node (defaults to using the tree's defined loader)
31970 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31971 expand : function(deep, anim, callback){
31972 if(this.loading){ // if an async load is already running, waiting til it's done
31974 var f = function(){
31975 if(!this.loading){ // done loading
31976 clearInterval(timer);
31977 this.expand(deep, anim, callback);
31979 }.createDelegate(this);
31980 timer = setInterval(f, 200);
31984 if(this.fireEvent("beforeload", this) === false){
31987 this.loading = true;
31988 this.ui.beforeLoad(this);
31989 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31991 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31995 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31999 * Returns true if this node is currently loading
32000 * @return {Boolean}
32002 isLoading : function(){
32003 return this.loading;
32006 loadComplete : function(deep, anim, callback){
32007 this.loading = false;
32008 this.loaded = true;
32009 this.ui.afterLoad(this);
32010 this.fireEvent("load", this);
32011 this.expand(deep, anim, callback);
32015 * Returns true if this node has been loaded
32016 * @return {Boolean}
32018 isLoaded : function(){
32019 return this.loaded;
32022 hasChildNodes : function(){
32023 if(!this.isLeaf() && !this.loaded){
32026 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32031 * Trigger a reload for this node
32032 * @param {Function} callback
32034 reload : function(callback){
32035 this.collapse(false, false);
32036 while(this.firstChild){
32037 this.removeChild(this.firstChild);
32039 this.childrenRendered = false;
32040 this.loaded = false;
32041 if(this.isHiddenRoot()){
32042 this.expanded = false;
32044 this.expand(false, false, callback);
32048 * Ext JS Library 1.1.1
32049 * Copyright(c) 2006-2007, Ext JS, LLC.
32051 * Originally Released Under LGPL - original licence link has changed is not relivant.
32054 * <script type="text/javascript">
32058 * @class Roo.tree.TreeNodeUI
32060 * @param {Object} node The node to render
32061 * The TreeNode UI implementation is separate from the
32062 * tree implementation. Unless you are customizing the tree UI,
32063 * you should never have to use this directly.
32065 Roo.tree.TreeNodeUI = function(node){
32067 this.rendered = false;
32068 this.animating = false;
32069 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32072 Roo.tree.TreeNodeUI.prototype = {
32073 removeChild : function(node){
32075 this.ctNode.removeChild(node.ui.getEl());
32079 beforeLoad : function(){
32080 this.addClass("x-tree-node-loading");
32083 afterLoad : function(){
32084 this.removeClass("x-tree-node-loading");
32087 onTextChange : function(node, text, oldText){
32089 this.textNode.innerHTML = text;
32093 onDisableChange : function(node, state){
32094 this.disabled = state;
32096 this.addClass("x-tree-node-disabled");
32098 this.removeClass("x-tree-node-disabled");
32102 onSelectedChange : function(state){
32105 this.addClass("x-tree-selected");
32108 this.removeClass("x-tree-selected");
32112 onMove : function(tree, node, oldParent, newParent, index, refNode){
32113 this.childIndent = null;
32115 var targetNode = newParent.ui.getContainer();
32116 if(!targetNode){//target not rendered
32117 this.holder = document.createElement("div");
32118 this.holder.appendChild(this.wrap);
32121 var insertBefore = refNode ? refNode.ui.getEl() : null;
32123 targetNode.insertBefore(this.wrap, insertBefore);
32125 targetNode.appendChild(this.wrap);
32127 this.node.renderIndent(true);
32131 addClass : function(cls){
32133 Roo.fly(this.elNode).addClass(cls);
32137 removeClass : function(cls){
32139 Roo.fly(this.elNode).removeClass(cls);
32143 remove : function(){
32145 this.holder = document.createElement("div");
32146 this.holder.appendChild(this.wrap);
32150 fireEvent : function(){
32151 return this.node.fireEvent.apply(this.node, arguments);
32154 initEvents : function(){
32155 this.node.on("move", this.onMove, this);
32156 var E = Roo.EventManager;
32157 var a = this.anchor;
32159 var el = Roo.fly(a, '_treeui');
32161 if(Roo.isOpera){ // opera render bug ignores the CSS
32162 el.setStyle("text-decoration", "none");
32165 el.on("click", this.onClick, this);
32166 el.on("dblclick", this.onDblClick, this);
32169 Roo.EventManager.on(this.checkbox,
32170 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32173 el.on("contextmenu", this.onContextMenu, this);
32175 var icon = Roo.fly(this.iconNode);
32176 icon.on("click", this.onClick, this);
32177 icon.on("dblclick", this.onDblClick, this);
32178 icon.on("contextmenu", this.onContextMenu, this);
32179 E.on(this.ecNode, "click", this.ecClick, this, true);
32181 if(this.node.disabled){
32182 this.addClass("x-tree-node-disabled");
32184 if(this.node.hidden){
32185 this.addClass("x-tree-node-disabled");
32187 var ot = this.node.getOwnerTree();
32188 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32189 if(dd && (!this.node.isRoot || ot.rootVisible)){
32190 Roo.dd.Registry.register(this.elNode, {
32192 handles: this.getDDHandles(),
32198 getDDHandles : function(){
32199 return [this.iconNode, this.textNode];
32204 this.wrap.style.display = "none";
32210 this.wrap.style.display = "";
32214 onContextMenu : function(e){
32215 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32216 e.preventDefault();
32218 this.fireEvent("contextmenu", this.node, e);
32222 onClick : function(e){
32227 if(this.fireEvent("beforeclick", this.node, e) !== false){
32228 if(!this.disabled && this.node.attributes.href){
32229 this.fireEvent("click", this.node, e);
32232 e.preventDefault();
32237 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32238 this.node.toggle();
32241 this.fireEvent("click", this.node, e);
32247 onDblClick : function(e){
32248 e.preventDefault();
32253 this.toggleCheck();
32255 if(!this.animating && this.node.hasChildNodes()){
32256 this.node.toggle();
32258 this.fireEvent("dblclick", this.node, e);
32261 onCheckChange : function(){
32262 var checked = this.checkbox.checked;
32263 this.node.attributes.checked = checked;
32264 this.fireEvent('checkchange', this.node, checked);
32267 ecClick : function(e){
32268 if(!this.animating && this.node.hasChildNodes()){
32269 this.node.toggle();
32273 startDrop : function(){
32274 this.dropping = true;
32277 // delayed drop so the click event doesn't get fired on a drop
32278 endDrop : function(){
32279 setTimeout(function(){
32280 this.dropping = false;
32281 }.createDelegate(this), 50);
32284 expand : function(){
32285 this.updateExpandIcon();
32286 this.ctNode.style.display = "";
32289 focus : function(){
32290 if(!this.node.preventHScroll){
32291 try{this.anchor.focus();
32293 }else if(!Roo.isIE){
32295 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32296 var l = noscroll.scrollLeft;
32297 this.anchor.focus();
32298 noscroll.scrollLeft = l;
32303 toggleCheck : function(value){
32304 var cb = this.checkbox;
32306 cb.checked = (value === undefined ? !cb.checked : value);
32312 this.anchor.blur();
32316 animExpand : function(callback){
32317 var ct = Roo.get(this.ctNode);
32319 if(!this.node.hasChildNodes()){
32320 this.updateExpandIcon();
32321 this.ctNode.style.display = "";
32322 Roo.callback(callback);
32325 this.animating = true;
32326 this.updateExpandIcon();
32329 callback : function(){
32330 this.animating = false;
32331 Roo.callback(callback);
32334 duration: this.node.ownerTree.duration || .25
32338 highlight : function(){
32339 var tree = this.node.getOwnerTree();
32340 Roo.fly(this.wrap).highlight(
32341 tree.hlColor || "C3DAF9",
32342 {endColor: tree.hlBaseColor}
32346 collapse : function(){
32347 this.updateExpandIcon();
32348 this.ctNode.style.display = "none";
32351 animCollapse : function(callback){
32352 var ct = Roo.get(this.ctNode);
32353 ct.enableDisplayMode('block');
32356 this.animating = true;
32357 this.updateExpandIcon();
32360 callback : function(){
32361 this.animating = false;
32362 Roo.callback(callback);
32365 duration: this.node.ownerTree.duration || .25
32369 getContainer : function(){
32370 return this.ctNode;
32373 getEl : function(){
32377 appendDDGhost : function(ghostNode){
32378 ghostNode.appendChild(this.elNode.cloneNode(true));
32381 getDDRepairXY : function(){
32382 return Roo.lib.Dom.getXY(this.iconNode);
32385 onRender : function(){
32389 render : function(bulkRender){
32390 var n = this.node, a = n.attributes;
32391 var targetNode = n.parentNode ?
32392 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32394 if(!this.rendered){
32395 this.rendered = true;
32397 this.renderElements(n, a, targetNode, bulkRender);
32400 if(this.textNode.setAttributeNS){
32401 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32403 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32406 this.textNode.setAttribute("ext:qtip", a.qtip);
32408 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32411 }else if(a.qtipCfg){
32412 a.qtipCfg.target = Roo.id(this.textNode);
32413 Roo.QuickTips.register(a.qtipCfg);
32416 if(!this.node.expanded){
32417 this.updateExpandIcon();
32420 if(bulkRender === true) {
32421 targetNode.appendChild(this.wrap);
32426 renderElements : function(n, a, targetNode, bulkRender){
32427 // add some indent caching, this helps performance when rendering a large tree
32428 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32429 var t = n.getOwnerTree();
32430 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32431 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32432 var cb = typeof a.checked == 'boolean';
32433 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32434 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32435 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32436 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32437 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32438 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32439 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32440 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32441 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32442 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32445 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32446 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32447 n.nextSibling.ui.getEl(), buf.join(""));
32449 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32452 this.elNode = this.wrap.childNodes[0];
32453 this.ctNode = this.wrap.childNodes[1];
32454 var cs = this.elNode.childNodes;
32455 this.indentNode = cs[0];
32456 this.ecNode = cs[1];
32457 this.iconNode = cs[2];
32460 this.checkbox = cs[3];
32463 this.anchor = cs[index];
32464 this.textNode = cs[index].firstChild;
32467 getAnchor : function(){
32468 return this.anchor;
32471 getTextEl : function(){
32472 return this.textNode;
32475 getIconEl : function(){
32476 return this.iconNode;
32479 isChecked : function(){
32480 return this.checkbox ? this.checkbox.checked : false;
32483 updateExpandIcon : function(){
32485 var n = this.node, c1, c2;
32486 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32487 var hasChild = n.hasChildNodes();
32491 c1 = "x-tree-node-collapsed";
32492 c2 = "x-tree-node-expanded";
32495 c1 = "x-tree-node-expanded";
32496 c2 = "x-tree-node-collapsed";
32499 this.removeClass("x-tree-node-leaf");
32500 this.wasLeaf = false;
32502 if(this.c1 != c1 || this.c2 != c2){
32503 Roo.fly(this.elNode).replaceClass(c1, c2);
32504 this.c1 = c1; this.c2 = c2;
32508 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32511 this.wasLeaf = true;
32514 var ecc = "x-tree-ec-icon "+cls;
32515 if(this.ecc != ecc){
32516 this.ecNode.className = ecc;
32522 getChildIndent : function(){
32523 if(!this.childIndent){
32527 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32529 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32531 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32536 this.childIndent = buf.join("");
32538 return this.childIndent;
32541 renderIndent : function(){
32544 var p = this.node.parentNode;
32546 indent = p.ui.getChildIndent();
32548 if(this.indentMarkup != indent){ // don't rerender if not required
32549 this.indentNode.innerHTML = indent;
32550 this.indentMarkup = indent;
32552 this.updateExpandIcon();
32557 Roo.tree.RootTreeNodeUI = function(){
32558 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32560 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32561 render : function(){
32562 if(!this.rendered){
32563 var targetNode = this.node.ownerTree.innerCt.dom;
32564 this.node.expanded = true;
32565 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32566 this.wrap = this.ctNode = targetNode.firstChild;
32569 collapse : function(){
32571 expand : function(){
32575 * Ext JS Library 1.1.1
32576 * Copyright(c) 2006-2007, Ext JS, LLC.
32578 * Originally Released Under LGPL - original licence link has changed is not relivant.
32581 * <script type="text/javascript">
32584 * @class Roo.tree.TreeLoader
32585 * @extends Roo.util.Observable
32586 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32587 * nodes from a specified URL. The response must be a javascript Array definition
32588 * who's elements are node definition objects. eg:
32590 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32591 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32594 * A server request is sent, and child nodes are loaded only when a node is expanded.
32595 * The loading node's id is passed to the server under the parameter name "node" to
32596 * enable the server to produce the correct child nodes.
32598 * To pass extra parameters, an event handler may be attached to the "beforeload"
32599 * event, and the parameters specified in the TreeLoader's baseParams property:
32601 myTreeLoader.on("beforeload", function(treeLoader, node) {
32602 this.baseParams.category = node.attributes.category;
32605 * This would pass an HTTP parameter called "category" to the server containing
32606 * the value of the Node's "category" attribute.
32608 * Creates a new Treeloader.
32609 * @param {Object} config A config object containing config properties.
32611 Roo.tree.TreeLoader = function(config){
32612 this.baseParams = {};
32613 this.requestMethod = "POST";
32614 Roo.apply(this, config);
32619 * @event beforeload
32620 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32621 * @param {Object} This TreeLoader object.
32622 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32623 * @param {Object} callback The callback function specified in the {@link #load} call.
32628 * Fires when the node has been successfuly loaded.
32629 * @param {Object} This TreeLoader object.
32630 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32631 * @param {Object} response The response object containing the data from the server.
32635 * @event loadexception
32636 * Fires if the network request failed.
32637 * @param {Object} This TreeLoader object.
32638 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32639 * @param {Object} response The response object containing the data from the server.
32641 loadexception : true,
32644 * Fires before a node is created, enabling you to return custom Node types
32645 * @param {Object} This TreeLoader object.
32646 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32651 Roo.tree.TreeLoader.superclass.constructor.call(this);
32654 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32656 * @cfg {String} dataUrl The URL from which to request a Json string which
32657 * specifies an array of node definition object representing the child nodes
32661 * @cfg {Object} baseParams (optional) An object containing properties which
32662 * specify HTTP parameters to be passed to each request for child nodes.
32665 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32666 * created by this loader. If the attributes sent by the server have an attribute in this object,
32667 * they take priority.
32670 * @cfg {Object} uiProviders (optional) An object containing properties which
32672 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32673 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32674 * <i>uiProvider</i> attribute of a returned child node is a string rather
32675 * than a reference to a TreeNodeUI implementation, this that string value
32676 * is used as a property name in the uiProviders object. You can define the provider named
32677 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32682 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32683 * child nodes before loading.
32685 clearOnLoad : true,
32688 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32689 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32690 * Grid query { data : [ .....] }
32695 * @cfg {String} queryParam (optional)
32696 * Name of the query as it will be passed on the querystring (defaults to 'node')
32697 * eg. the request will be ?node=[id]
32704 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32705 * This is called automatically when a node is expanded, but may be used to reload
32706 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32707 * @param {Roo.tree.TreeNode} node
32708 * @param {Function} callback
32710 load : function(node, callback){
32711 if(this.clearOnLoad){
32712 while(node.firstChild){
32713 node.removeChild(node.firstChild);
32716 if(node.attributes.children){ // preloaded json children
32717 var cs = node.attributes.children;
32718 for(var i = 0, len = cs.length; i < len; i++){
32719 node.appendChild(this.createNode(cs[i]));
32721 if(typeof callback == "function"){
32724 }else if(this.dataUrl){
32725 this.requestData(node, callback);
32729 getParams: function(node){
32730 var buf = [], bp = this.baseParams;
32731 for(var key in bp){
32732 if(typeof bp[key] != "function"){
32733 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32736 var n = this.queryParam === false ? 'node' : this.queryParam;
32737 buf.push(n + "=", encodeURIComponent(node.id));
32738 return buf.join("");
32741 requestData : function(node, callback){
32742 if(this.fireEvent("beforeload", this, node, callback) !== false){
32743 this.transId = Roo.Ajax.request({
32744 method:this.requestMethod,
32745 url: this.dataUrl||this.url,
32746 success: this.handleResponse,
32747 failure: this.handleFailure,
32749 argument: {callback: callback, node: node},
32750 params: this.getParams(node)
32753 // if the load is cancelled, make sure we notify
32754 // the node that we are done
32755 if(typeof callback == "function"){
32761 isLoading : function(){
32762 return this.transId ? true : false;
32765 abort : function(){
32766 if(this.isLoading()){
32767 Roo.Ajax.abort(this.transId);
32772 createNode : function(attr){
32773 // apply baseAttrs, nice idea Corey!
32774 if(this.baseAttrs){
32775 Roo.applyIf(attr, this.baseAttrs);
32777 if(this.applyLoader !== false){
32778 attr.loader = this;
32780 // uiProvider = depreciated..
32782 if(typeof(attr.uiProvider) == 'string'){
32783 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32784 /** eval:var:attr */ eval(attr.uiProvider);
32786 if(typeof(this.uiProviders['default']) != 'undefined') {
32787 attr.uiProvider = this.uiProviders['default'];
32790 this.fireEvent('create', this, attr);
32792 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32794 new Roo.tree.TreeNode(attr) :
32795 new Roo.tree.AsyncTreeNode(attr));
32798 processResponse : function(response, node, callback){
32799 var json = response.responseText;
32802 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32803 if (this.root !== false) {
32807 for(var i = 0, len = o.length; i < len; i++){
32808 var n = this.createNode(o[i]);
32810 node.appendChild(n);
32813 if(typeof callback == "function"){
32814 callback(this, node);
32817 this.handleFailure(response);
32821 handleResponse : function(response){
32822 this.transId = false;
32823 var a = response.argument;
32824 this.processResponse(response, a.node, a.callback);
32825 this.fireEvent("load", this, a.node, response);
32828 handleFailure : function(response){
32829 this.transId = false;
32830 var a = response.argument;
32831 this.fireEvent("loadexception", this, a.node, response);
32832 if(typeof a.callback == "function"){
32833 a.callback(this, a.node);
32838 * Ext JS Library 1.1.1
32839 * Copyright(c) 2006-2007, Ext JS, LLC.
32841 * Originally Released Under LGPL - original licence link has changed is not relivant.
32844 * <script type="text/javascript">
32848 * @class Roo.tree.TreeFilter
32849 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32850 * @param {TreePanel} tree
32851 * @param {Object} config (optional)
32853 Roo.tree.TreeFilter = function(tree, config){
32855 this.filtered = {};
32856 Roo.apply(this, config);
32859 Roo.tree.TreeFilter.prototype = {
32866 * Filter the data by a specific attribute.
32867 * @param {String/RegExp} value Either string that the attribute value
32868 * should start with or a RegExp to test against the attribute
32869 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32870 * @param {TreeNode} startNode (optional) The node to start the filter at.
32872 filter : function(value, attr, startNode){
32873 attr = attr || "text";
32875 if(typeof value == "string"){
32876 var vlen = value.length;
32877 // auto clear empty filter
32878 if(vlen == 0 && this.clearBlank){
32882 value = value.toLowerCase();
32884 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32886 }else if(value.exec){ // regex?
32888 return value.test(n.attributes[attr]);
32891 throw 'Illegal filter type, must be string or regex';
32893 this.filterBy(f, null, startNode);
32897 * Filter by a function. The passed function will be called with each
32898 * node in the tree (or from the startNode). If the function returns true, the node is kept
32899 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32900 * @param {Function} fn The filter function
32901 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32903 filterBy : function(fn, scope, startNode){
32904 startNode = startNode || this.tree.root;
32905 if(this.autoClear){
32908 var af = this.filtered, rv = this.reverse;
32909 var f = function(n){
32910 if(n == startNode){
32916 var m = fn.call(scope || n, n);
32924 startNode.cascade(f);
32927 if(typeof id != "function"){
32929 if(n && n.parentNode){
32930 n.parentNode.removeChild(n);
32938 * Clears the current filter. Note: with the "remove" option
32939 * set a filter cannot be cleared.
32941 clear : function(){
32943 var af = this.filtered;
32945 if(typeof id != "function"){
32952 this.filtered = {};
32957 * Ext JS Library 1.1.1
32958 * Copyright(c) 2006-2007, Ext JS, LLC.
32960 * Originally Released Under LGPL - original licence link has changed is not relivant.
32963 * <script type="text/javascript">
32968 * @class Roo.tree.TreeSorter
32969 * Provides sorting of nodes in a TreePanel
32971 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32972 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32973 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32974 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32975 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32976 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32978 * @param {TreePanel} tree
32979 * @param {Object} config
32981 Roo.tree.TreeSorter = function(tree, config){
32982 Roo.apply(this, config);
32983 tree.on("beforechildrenrendered", this.doSort, this);
32984 tree.on("append", this.updateSort, this);
32985 tree.on("insert", this.updateSort, this);
32987 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32988 var p = this.property || "text";
32989 var sortType = this.sortType;
32990 var fs = this.folderSort;
32991 var cs = this.caseSensitive === true;
32992 var leafAttr = this.leafAttr || 'leaf';
32994 this.sortFn = function(n1, n2){
32996 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32999 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33003 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33004 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33006 return dsc ? +1 : -1;
33008 return dsc ? -1 : +1;
33015 Roo.tree.TreeSorter.prototype = {
33016 doSort : function(node){
33017 node.sort(this.sortFn);
33020 compareNodes : function(n1, n2){
33021 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33024 updateSort : function(tree, node){
33025 if(node.childrenRendered){
33026 this.doSort.defer(1, this, [node]);
33031 * Ext JS Library 1.1.1
33032 * Copyright(c) 2006-2007, Ext JS, LLC.
33034 * Originally Released Under LGPL - original licence link has changed is not relivant.
33037 * <script type="text/javascript">
33040 if(Roo.dd.DropZone){
33042 Roo.tree.TreeDropZone = function(tree, config){
33043 this.allowParentInsert = false;
33044 this.allowContainerDrop = false;
33045 this.appendOnly = false;
33046 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33048 this.lastInsertClass = "x-tree-no-status";
33049 this.dragOverData = {};
33052 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33053 ddGroup : "TreeDD",
33055 expandDelay : 1000,
33057 expandNode : function(node){
33058 if(node.hasChildNodes() && !node.isExpanded()){
33059 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33063 queueExpand : function(node){
33064 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33067 cancelExpand : function(){
33068 if(this.expandProcId){
33069 clearTimeout(this.expandProcId);
33070 this.expandProcId = false;
33074 isValidDropPoint : function(n, pt, dd, e, data){
33075 if(!n || !data){ return false; }
33076 var targetNode = n.node;
33077 var dropNode = data.node;
33078 // default drop rules
33079 if(!(targetNode && targetNode.isTarget && pt)){
33082 if(pt == "append" && targetNode.allowChildren === false){
33085 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33088 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33091 // reuse the object
33092 var overEvent = this.dragOverData;
33093 overEvent.tree = this.tree;
33094 overEvent.target = targetNode;
33095 overEvent.data = data;
33096 overEvent.point = pt;
33097 overEvent.source = dd;
33098 overEvent.rawEvent = e;
33099 overEvent.dropNode = dropNode;
33100 overEvent.cancel = false;
33101 var result = this.tree.fireEvent("nodedragover", overEvent);
33102 return overEvent.cancel === false && result !== false;
33105 getDropPoint : function(e, n, dd){
33108 return tn.allowChildren !== false ? "append" : false; // always append for root
33110 var dragEl = n.ddel;
33111 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33112 var y = Roo.lib.Event.getPageY(e);
33113 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33115 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33116 var noAppend = tn.allowChildren === false;
33117 if(this.appendOnly || tn.parentNode.allowChildren === false){
33118 return noAppend ? false : "append";
33120 var noBelow = false;
33121 if(!this.allowParentInsert){
33122 noBelow = tn.hasChildNodes() && tn.isExpanded();
33124 var q = (b - t) / (noAppend ? 2 : 3);
33125 if(y >= t && y < (t + q)){
33127 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33134 onNodeEnter : function(n, dd, e, data){
33135 this.cancelExpand();
33138 onNodeOver : function(n, dd, e, data){
33139 var pt = this.getDropPoint(e, n, dd);
33142 // auto node expand check
33143 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33144 this.queueExpand(node);
33145 }else if(pt != "append"){
33146 this.cancelExpand();
33149 // set the insert point style on the target node
33150 var returnCls = this.dropNotAllowed;
33151 if(this.isValidDropPoint(n, pt, dd, e, data)){
33156 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33157 cls = "x-tree-drag-insert-above";
33158 }else if(pt == "below"){
33159 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33160 cls = "x-tree-drag-insert-below";
33162 returnCls = "x-tree-drop-ok-append";
33163 cls = "x-tree-drag-append";
33165 if(this.lastInsertClass != cls){
33166 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33167 this.lastInsertClass = cls;
33174 onNodeOut : function(n, dd, e, data){
33175 this.cancelExpand();
33176 this.removeDropIndicators(n);
33179 onNodeDrop : function(n, dd, e, data){
33180 var point = this.getDropPoint(e, n, dd);
33181 var targetNode = n.node;
33182 targetNode.ui.startDrop();
33183 if(!this.isValidDropPoint(n, point, dd, e, data)){
33184 targetNode.ui.endDrop();
33187 // first try to find the drop node
33188 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33191 target: targetNode,
33196 dropNode: dropNode,
33199 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33200 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33201 targetNode.ui.endDrop();
33204 // allow target changing
33205 targetNode = dropEvent.target;
33206 if(point == "append" && !targetNode.isExpanded()){
33207 targetNode.expand(false, null, function(){
33208 this.completeDrop(dropEvent);
33209 }.createDelegate(this));
33211 this.completeDrop(dropEvent);
33216 completeDrop : function(de){
33217 var ns = de.dropNode, p = de.point, t = de.target;
33218 if(!(ns instanceof Array)){
33222 for(var i = 0, len = ns.length; i < len; i++){
33225 t.parentNode.insertBefore(n, t);
33226 }else if(p == "below"){
33227 t.parentNode.insertBefore(n, t.nextSibling);
33233 if(this.tree.hlDrop){
33237 this.tree.fireEvent("nodedrop", de);
33240 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33241 if(this.tree.hlDrop){
33242 dropNode.ui.focus();
33243 dropNode.ui.highlight();
33245 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33248 getTree : function(){
33252 removeDropIndicators : function(n){
33255 Roo.fly(el).removeClass([
33256 "x-tree-drag-insert-above",
33257 "x-tree-drag-insert-below",
33258 "x-tree-drag-append"]);
33259 this.lastInsertClass = "_noclass";
33263 beforeDragDrop : function(target, e, id){
33264 this.cancelExpand();
33268 afterRepair : function(data){
33269 if(data && Roo.enableFx){
33270 data.node.ui.highlight();
33279 * Ext JS Library 1.1.1
33280 * Copyright(c) 2006-2007, Ext JS, LLC.
33282 * Originally Released Under LGPL - original licence link has changed is not relivant.
33285 * <script type="text/javascript">
33289 if(Roo.dd.DragZone){
33290 Roo.tree.TreeDragZone = function(tree, config){
33291 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33295 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33296 ddGroup : "TreeDD",
33298 onBeforeDrag : function(data, e){
33300 return n && n.draggable && !n.disabled;
33303 onInitDrag : function(e){
33304 var data = this.dragData;
33305 this.tree.getSelectionModel().select(data.node);
33306 this.proxy.update("");
33307 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33308 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33311 getRepairXY : function(e, data){
33312 return data.node.ui.getDDRepairXY();
33315 onEndDrag : function(data, e){
33316 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33319 onValidDrop : function(dd, e, id){
33320 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33324 beforeInvalidDrop : function(e, id){
33325 // this scrolls the original position back into view
33326 var sm = this.tree.getSelectionModel();
33327 sm.clearSelections();
33328 sm.select(this.dragData.node);
33333 * Ext JS Library 1.1.1
33334 * Copyright(c) 2006-2007, Ext JS, LLC.
33336 * Originally Released Under LGPL - original licence link has changed is not relivant.
33339 * <script type="text/javascript">
33342 * @class Roo.tree.TreeEditor
33343 * @extends Roo.Editor
33344 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33345 * as the editor field.
33347 * @param {TreePanel} tree
33348 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33350 Roo.tree.TreeEditor = function(tree, config){
33351 config = config || {};
33352 var field = config.events ? config : new Roo.form.TextField(config);
33353 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33357 tree.on('beforeclick', this.beforeNodeClick, this);
33358 tree.getTreeEl().on('mousedown', this.hide, this);
33359 this.on('complete', this.updateNode, this);
33360 this.on('beforestartedit', this.fitToTree, this);
33361 this.on('startedit', this.bindScroll, this, {delay:10});
33362 this.on('specialkey', this.onSpecialKey, this);
33365 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33367 * @cfg {String} alignment
33368 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33374 * @cfg {Boolean} hideEl
33375 * True to hide the bound element while the editor is displayed (defaults to false)
33379 * @cfg {String} cls
33380 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33382 cls: "x-small-editor x-tree-editor",
33384 * @cfg {Boolean} shim
33385 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33391 * @cfg {Number} maxWidth
33392 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33393 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33394 * scroll and client offsets into account prior to each edit.
33401 fitToTree : function(ed, el){
33402 var td = this.tree.getTreeEl().dom, nd = el.dom;
33403 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33404 td.scrollLeft = nd.offsetLeft;
33408 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33409 this.setSize(w, '');
33413 triggerEdit : function(node){
33414 this.completeEdit();
33415 this.editNode = node;
33416 this.startEdit(node.ui.textNode, node.text);
33420 bindScroll : function(){
33421 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33425 beforeNodeClick : function(node, e){
33426 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33427 this.lastClick = new Date();
33428 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33430 this.triggerEdit(node);
33436 updateNode : function(ed, value){
33437 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33438 this.editNode.setText(value);
33442 onHide : function(){
33443 Roo.tree.TreeEditor.superclass.onHide.call(this);
33445 this.editNode.ui.focus();
33450 onSpecialKey : function(field, e){
33451 var k = e.getKey();
33455 }else if(k == e.ENTER && !e.hasModifier()){
33457 this.completeEdit();
33460 });//<Script type="text/javascript">
33463 * Ext JS Library 1.1.1
33464 * Copyright(c) 2006-2007, Ext JS, LLC.
33466 * Originally Released Under LGPL - original licence link has changed is not relivant.
33469 * <script type="text/javascript">
33473 * Not documented??? - probably should be...
33476 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33477 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33479 renderElements : function(n, a, targetNode, bulkRender){
33480 //consel.log("renderElements?");
33481 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33483 var t = n.getOwnerTree();
33484 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33486 var cols = t.columns;
33487 var bw = t.borderWidth;
33489 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33490 var cb = typeof a.checked == "boolean";
33491 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33492 var colcls = 'x-t-' + tid + '-c0';
33494 '<li class="x-tree-node">',
33497 '<div class="x-tree-node-el ', a.cls,'">',
33499 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33502 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33503 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33504 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33505 (a.icon ? ' x-tree-node-inline-icon' : ''),
33506 (a.iconCls ? ' '+a.iconCls : ''),
33507 '" unselectable="on" />',
33508 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33509 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33511 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33512 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33513 '<span unselectable="on" qtip="' + tx + '">',
33517 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33518 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33520 for(var i = 1, len = cols.length; i < len; i++){
33522 colcls = 'x-t-' + tid + '-c' +i;
33523 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33524 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33525 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33531 '<div class="x-clear"></div></div>',
33532 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33535 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33536 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33537 n.nextSibling.ui.getEl(), buf.join(""));
33539 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33541 var el = this.wrap.firstChild;
33543 this.elNode = el.firstChild;
33544 this.ranchor = el.childNodes[1];
33545 this.ctNode = this.wrap.childNodes[1];
33546 var cs = el.firstChild.childNodes;
33547 this.indentNode = cs[0];
33548 this.ecNode = cs[1];
33549 this.iconNode = cs[2];
33552 this.checkbox = cs[3];
33555 this.anchor = cs[index];
33557 this.textNode = cs[index].firstChild;
33559 //el.on("click", this.onClick, this);
33560 //el.on("dblclick", this.onDblClick, this);
33563 // console.log(this);
33565 initEvents : function(){
33566 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33569 var a = this.ranchor;
33571 var el = Roo.get(a);
33573 if(Roo.isOpera){ // opera render bug ignores the CSS
33574 el.setStyle("text-decoration", "none");
33577 el.on("click", this.onClick, this);
33578 el.on("dblclick", this.onDblClick, this);
33579 el.on("contextmenu", this.onContextMenu, this);
33583 /*onSelectedChange : function(state){
33586 this.addClass("x-tree-selected");
33589 this.removeClass("x-tree-selected");
33592 addClass : function(cls){
33594 Roo.fly(this.elRow).addClass(cls);
33600 removeClass : function(cls){
33602 Roo.fly(this.elRow).removeClass(cls);
33608 });//<Script type="text/javascript">
33612 * Ext JS Library 1.1.1
33613 * Copyright(c) 2006-2007, Ext JS, LLC.
33615 * Originally Released Under LGPL - original licence link has changed is not relivant.
33618 * <script type="text/javascript">
33623 * @class Roo.tree.ColumnTree
33624 * @extends Roo.data.TreePanel
33625 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33626 * @cfg {int} borderWidth compined right/left border allowance
33628 * @param {String/HTMLElement/Element} el The container element
33629 * @param {Object} config
33631 Roo.tree.ColumnTree = function(el, config)
33633 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33637 * Fire this event on a container when it resizes
33638 * @param {int} w Width
33639 * @param {int} h Height
33643 this.on('resize', this.onResize, this);
33646 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33650 borderWidth: Roo.isBorderBox ? 0 : 2,
33653 render : function(){
33654 // add the header.....
33656 Roo.tree.ColumnTree.superclass.render.apply(this);
33658 this.el.addClass('x-column-tree');
33660 this.headers = this.el.createChild(
33661 {cls:'x-tree-headers'},this.innerCt.dom);
33663 var cols = this.columns, c;
33664 var totalWidth = 0;
33666 var len = cols.length;
33667 for(var i = 0; i < len; i++){
33669 totalWidth += c.width;
33670 this.headEls.push(this.headers.createChild({
33671 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33673 cls:'x-tree-hd-text',
33676 style:'width:'+(c.width-this.borderWidth)+'px;'
33679 this.headers.createChild({cls:'x-clear'});
33680 // prevent floats from wrapping when clipped
33681 this.headers.setWidth(totalWidth);
33682 //this.innerCt.setWidth(totalWidth);
33683 this.innerCt.setStyle({ overflow: 'auto' });
33684 this.onResize(this.width, this.height);
33688 onResize : function(w,h)
33693 this.innerCt.setWidth(this.width);
33694 this.innerCt.setHeight(this.height-20);
33697 var cols = this.columns, c;
33698 var totalWidth = 0;
33700 var len = cols.length;
33701 for(var i = 0; i < len; i++){
33703 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33704 // it's the expander..
33705 expEl = this.headEls[i];
33708 totalWidth += c.width;
33712 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33714 this.headers.setWidth(w-20);
33723 * Ext JS Library 1.1.1
33724 * Copyright(c) 2006-2007, Ext JS, LLC.
33726 * Originally Released Under LGPL - original licence link has changed is not relivant.
33729 * <script type="text/javascript">
33733 * @class Roo.menu.Menu
33734 * @extends Roo.util.Observable
33735 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33736 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33738 * Creates a new Menu
33739 * @param {Object} config Configuration options
33741 Roo.menu.Menu = function(config){
33742 Roo.apply(this, config);
33743 this.id = this.id || Roo.id();
33746 * @event beforeshow
33747 * Fires before this menu is displayed
33748 * @param {Roo.menu.Menu} this
33752 * @event beforehide
33753 * Fires before this menu is hidden
33754 * @param {Roo.menu.Menu} this
33759 * Fires after this menu is displayed
33760 * @param {Roo.menu.Menu} this
33765 * Fires after this menu is hidden
33766 * @param {Roo.menu.Menu} this
33771 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33772 * @param {Roo.menu.Menu} this
33773 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33774 * @param {Roo.EventObject} e
33779 * Fires when the mouse is hovering over this menu
33780 * @param {Roo.menu.Menu} this
33781 * @param {Roo.EventObject} e
33782 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33787 * Fires when the mouse exits this menu
33788 * @param {Roo.menu.Menu} this
33789 * @param {Roo.EventObject} e
33790 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33795 * Fires when a menu item contained in this menu is clicked
33796 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33797 * @param {Roo.EventObject} e
33801 if (this.registerMenu) {
33802 Roo.menu.MenuMgr.register(this);
33805 var mis = this.items;
33806 this.items = new Roo.util.MixedCollection();
33808 this.add.apply(this, mis);
33812 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33814 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33818 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33819 * for bottom-right shadow (defaults to "sides")
33823 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33824 * this menu (defaults to "tl-tr?")
33826 subMenuAlign : "tl-tr?",
33828 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33829 * relative to its element of origin (defaults to "tl-bl?")
33831 defaultAlign : "tl-bl?",
33833 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33835 allowOtherMenus : false,
33837 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33839 registerMenu : true,
33844 render : function(){
33848 var el = this.el = new Roo.Layer({
33850 shadow:this.shadow,
33852 parentEl: this.parentEl || document.body,
33856 this.keyNav = new Roo.menu.MenuNav(this);
33859 el.addClass("x-menu-plain");
33862 el.addClass(this.cls);
33864 // generic focus element
33865 this.focusEl = el.createChild({
33866 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33868 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33869 ul.on("click", this.onClick, this);
33870 ul.on("mouseover", this.onMouseOver, this);
33871 ul.on("mouseout", this.onMouseOut, this);
33872 this.items.each(function(item){
33873 var li = document.createElement("li");
33874 li.className = "x-menu-list-item";
33875 ul.dom.appendChild(li);
33876 item.render(li, this);
33883 autoWidth : function(){
33884 var el = this.el, ul = this.ul;
33888 var w = this.width;
33891 }else if(Roo.isIE){
33892 el.setWidth(this.minWidth);
33893 var t = el.dom.offsetWidth; // force recalc
33894 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33899 delayAutoWidth : function(){
33902 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33904 this.awTask.delay(20);
33909 findTargetItem : function(e){
33910 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33911 if(t && t.menuItemId){
33912 return this.items.get(t.menuItemId);
33917 onClick : function(e){
33919 if(t = this.findTargetItem(e)){
33921 this.fireEvent("click", this, t, e);
33926 setActiveItem : function(item, autoExpand){
33927 if(item != this.activeItem){
33928 if(this.activeItem){
33929 this.activeItem.deactivate();
33931 this.activeItem = item;
33932 item.activate(autoExpand);
33933 }else if(autoExpand){
33939 tryActivate : function(start, step){
33940 var items = this.items;
33941 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33942 var item = items.get(i);
33943 if(!item.disabled && item.canActivate){
33944 this.setActiveItem(item, false);
33952 onMouseOver : function(e){
33954 if(t = this.findTargetItem(e)){
33955 if(t.canActivate && !t.disabled){
33956 this.setActiveItem(t, true);
33959 this.fireEvent("mouseover", this, e, t);
33963 onMouseOut : function(e){
33965 if(t = this.findTargetItem(e)){
33966 if(t == this.activeItem && t.shouldDeactivate(e)){
33967 this.activeItem.deactivate();
33968 delete this.activeItem;
33971 this.fireEvent("mouseout", this, e, t);
33975 * Read-only. Returns true if the menu is currently displayed, else false.
33978 isVisible : function(){
33979 return this.el && !this.hidden;
33983 * Displays this menu relative to another element
33984 * @param {String/HTMLElement/Roo.Element} element The element to align to
33985 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33986 * the element (defaults to this.defaultAlign)
33987 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33989 show : function(el, pos, parentMenu){
33990 this.parentMenu = parentMenu;
33994 this.fireEvent("beforeshow", this);
33995 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33999 * Displays this menu at a specific xy position
34000 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34001 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34003 showAt : function(xy, parentMenu, /* private: */_e){
34004 this.parentMenu = parentMenu;
34009 this.fireEvent("beforeshow", this);
34010 xy = this.el.adjustForConstraints(xy);
34014 this.hidden = false;
34016 this.fireEvent("show", this);
34019 focus : function(){
34021 this.doFocus.defer(50, this);
34025 doFocus : function(){
34027 this.focusEl.focus();
34032 * Hides this menu and optionally all parent menus
34033 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34035 hide : function(deep){
34036 if(this.el && this.isVisible()){
34037 this.fireEvent("beforehide", this);
34038 if(this.activeItem){
34039 this.activeItem.deactivate();
34040 this.activeItem = null;
34043 this.hidden = true;
34044 this.fireEvent("hide", this);
34046 if(deep === true && this.parentMenu){
34047 this.parentMenu.hide(true);
34052 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34053 * Any of the following are valid:
34055 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34056 * <li>An HTMLElement object which will be converted to a menu item</li>
34057 * <li>A menu item config object that will be created as a new menu item</li>
34058 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34059 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34064 var menu = new Roo.menu.Menu();
34066 // Create a menu item to add by reference
34067 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34069 // Add a bunch of items at once using different methods.
34070 // Only the last item added will be returned.
34071 var item = menu.add(
34072 menuItem, // add existing item by ref
34073 'Dynamic Item', // new TextItem
34074 '-', // new separator
34075 { text: 'Config Item' } // new item by config
34078 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34079 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34082 var a = arguments, l = a.length, item;
34083 for(var i = 0; i < l; i++){
34085 if ((typeof(el) == "object") && el.xtype && el.xns) {
34086 el = Roo.factory(el, Roo.menu);
34089 if(el.render){ // some kind of Item
34090 item = this.addItem(el);
34091 }else if(typeof el == "string"){ // string
34092 if(el == "separator" || el == "-"){
34093 item = this.addSeparator();
34095 item = this.addText(el);
34097 }else if(el.tagName || el.el){ // element
34098 item = this.addElement(el);
34099 }else if(typeof el == "object"){ // must be menu item config?
34100 item = this.addMenuItem(el);
34107 * Returns this menu's underlying {@link Roo.Element} object
34108 * @return {Roo.Element} The element
34110 getEl : function(){
34118 * Adds a separator bar to the menu
34119 * @return {Roo.menu.Item} The menu item that was added
34121 addSeparator : function(){
34122 return this.addItem(new Roo.menu.Separator());
34126 * Adds an {@link Roo.Element} object to the menu
34127 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34128 * @return {Roo.menu.Item} The menu item that was added
34130 addElement : function(el){
34131 return this.addItem(new Roo.menu.BaseItem(el));
34135 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34136 * @param {Roo.menu.Item} item The menu item to add
34137 * @return {Roo.menu.Item} The menu item that was added
34139 addItem : function(item){
34140 this.items.add(item);
34142 var li = document.createElement("li");
34143 li.className = "x-menu-list-item";
34144 this.ul.dom.appendChild(li);
34145 item.render(li, this);
34146 this.delayAutoWidth();
34152 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34153 * @param {Object} config A MenuItem config object
34154 * @return {Roo.menu.Item} The menu item that was added
34156 addMenuItem : function(config){
34157 if(!(config instanceof Roo.menu.Item)){
34158 if(typeof config.checked == "boolean"){ // must be check menu item config?
34159 config = new Roo.menu.CheckItem(config);
34161 config = new Roo.menu.Item(config);
34164 return this.addItem(config);
34168 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34169 * @param {String} text The text to display in the menu item
34170 * @return {Roo.menu.Item} The menu item that was added
34172 addText : function(text){
34173 return this.addItem(new Roo.menu.TextItem({ text : text }));
34177 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34178 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34179 * @param {Roo.menu.Item} item The menu item to add
34180 * @return {Roo.menu.Item} The menu item that was added
34182 insert : function(index, item){
34183 this.items.insert(index, item);
34185 var li = document.createElement("li");
34186 li.className = "x-menu-list-item";
34187 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34188 item.render(li, this);
34189 this.delayAutoWidth();
34195 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34196 * @param {Roo.menu.Item} item The menu item to remove
34198 remove : function(item){
34199 this.items.removeKey(item.id);
34204 * Removes and destroys all items in the menu
34206 removeAll : function(){
34208 while(f = this.items.first()){
34214 // MenuNav is a private utility class used internally by the Menu
34215 Roo.menu.MenuNav = function(menu){
34216 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34217 this.scope = this.menu = menu;
34220 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34221 doRelay : function(e, h){
34222 var k = e.getKey();
34223 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34224 this.menu.tryActivate(0, 1);
34227 return h.call(this.scope || this, e, this.menu);
34230 up : function(e, m){
34231 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34232 m.tryActivate(m.items.length-1, -1);
34236 down : function(e, m){
34237 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34238 m.tryActivate(0, 1);
34242 right : function(e, m){
34244 m.activeItem.expandMenu(true);
34248 left : function(e, m){
34250 if(m.parentMenu && m.parentMenu.activeItem){
34251 m.parentMenu.activeItem.activate();
34255 enter : function(e, m){
34257 e.stopPropagation();
34258 m.activeItem.onClick(e);
34259 m.fireEvent("click", this, m.activeItem);
34265 * Ext JS Library 1.1.1
34266 * Copyright(c) 2006-2007, Ext JS, LLC.
34268 * Originally Released Under LGPL - original licence link has changed is not relivant.
34271 * <script type="text/javascript">
34275 * @class Roo.menu.MenuMgr
34276 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34279 Roo.menu.MenuMgr = function(){
34280 var menus, active, groups = {}, attached = false, lastShow = new Date();
34282 // private - called when first menu is created
34285 active = new Roo.util.MixedCollection();
34286 Roo.get(document).addKeyListener(27, function(){
34287 if(active.length > 0){
34294 function hideAll(){
34295 if(active && active.length > 0){
34296 var c = active.clone();
34297 c.each(function(m){
34304 function onHide(m){
34306 if(active.length < 1){
34307 Roo.get(document).un("mousedown", onMouseDown);
34313 function onShow(m){
34314 var last = active.last();
34315 lastShow = new Date();
34318 Roo.get(document).on("mousedown", onMouseDown);
34322 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34323 m.parentMenu.activeChild = m;
34324 }else if(last && last.isVisible()){
34325 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34330 function onBeforeHide(m){
34332 m.activeChild.hide();
34334 if(m.autoHideTimer){
34335 clearTimeout(m.autoHideTimer);
34336 delete m.autoHideTimer;
34341 function onBeforeShow(m){
34342 var pm = m.parentMenu;
34343 if(!pm && !m.allowOtherMenus){
34345 }else if(pm && pm.activeChild && active != m){
34346 pm.activeChild.hide();
34351 function onMouseDown(e){
34352 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34358 function onBeforeCheck(mi, state){
34360 var g = groups[mi.group];
34361 for(var i = 0, l = g.length; i < l; i++){
34363 g[i].setChecked(false);
34372 * Hides all menus that are currently visible
34374 hideAll : function(){
34379 register : function(menu){
34383 menus[menu.id] = menu;
34384 menu.on("beforehide", onBeforeHide);
34385 menu.on("hide", onHide);
34386 menu.on("beforeshow", onBeforeShow);
34387 menu.on("show", onShow);
34388 var g = menu.group;
34389 if(g && menu.events["checkchange"]){
34393 groups[g].push(menu);
34394 menu.on("checkchange", onCheck);
34399 * Returns a {@link Roo.menu.Menu} object
34400 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34401 * be used to generate and return a new Menu instance.
34403 get : function(menu){
34404 if(typeof menu == "string"){ // menu id
34405 return menus[menu];
34406 }else if(menu.events){ // menu instance
34408 }else if(typeof menu.length == 'number'){ // array of menu items?
34409 return new Roo.menu.Menu({items:menu});
34410 }else{ // otherwise, must be a config
34411 return new Roo.menu.Menu(menu);
34416 unregister : function(menu){
34417 delete menus[menu.id];
34418 menu.un("beforehide", onBeforeHide);
34419 menu.un("hide", onHide);
34420 menu.un("beforeshow", onBeforeShow);
34421 menu.un("show", onShow);
34422 var g = menu.group;
34423 if(g && menu.events["checkchange"]){
34424 groups[g].remove(menu);
34425 menu.un("checkchange", onCheck);
34430 registerCheckable : function(menuItem){
34431 var g = menuItem.group;
34436 groups[g].push(menuItem);
34437 menuItem.on("beforecheckchange", onBeforeCheck);
34442 unregisterCheckable : function(menuItem){
34443 var g = menuItem.group;
34445 groups[g].remove(menuItem);
34446 menuItem.un("beforecheckchange", onBeforeCheck);
34452 * Ext JS Library 1.1.1
34453 * Copyright(c) 2006-2007, Ext JS, LLC.
34455 * Originally Released Under LGPL - original licence link has changed is not relivant.
34458 * <script type="text/javascript">
34463 * @class Roo.menu.BaseItem
34464 * @extends Roo.Component
34465 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34466 * management and base configuration options shared by all menu components.
34468 * Creates a new BaseItem
34469 * @param {Object} config Configuration options
34471 Roo.menu.BaseItem = function(config){
34472 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34477 * Fires when this item is clicked
34478 * @param {Roo.menu.BaseItem} this
34479 * @param {Roo.EventObject} e
34484 * Fires when this item is activated
34485 * @param {Roo.menu.BaseItem} this
34489 * @event deactivate
34490 * Fires when this item is deactivated
34491 * @param {Roo.menu.BaseItem} this
34497 this.on("click", this.handler, this.scope, true);
34501 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34503 * @cfg {Function} handler
34504 * A function that will handle the click event of this menu item (defaults to undefined)
34507 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34509 canActivate : false,
34511 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34513 activeClass : "x-menu-item-active",
34515 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34517 hideOnClick : true,
34519 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34524 ctype: "Roo.menu.BaseItem",
34527 actionMode : "container",
34530 render : function(container, parentMenu){
34531 this.parentMenu = parentMenu;
34532 Roo.menu.BaseItem.superclass.render.call(this, container);
34533 this.container.menuItemId = this.id;
34537 onRender : function(container, position){
34538 this.el = Roo.get(this.el);
34539 container.dom.appendChild(this.el.dom);
34543 onClick : function(e){
34544 if(!this.disabled && this.fireEvent("click", this, e) !== false
34545 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34546 this.handleClick(e);
34553 activate : function(){
34557 var li = this.container;
34558 li.addClass(this.activeClass);
34559 this.region = li.getRegion().adjust(2, 2, -2, -2);
34560 this.fireEvent("activate", this);
34565 deactivate : function(){
34566 this.container.removeClass(this.activeClass);
34567 this.fireEvent("deactivate", this);
34571 shouldDeactivate : function(e){
34572 return !this.region || !this.region.contains(e.getPoint());
34576 handleClick : function(e){
34577 if(this.hideOnClick){
34578 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34583 expandMenu : function(autoActivate){
34588 hideMenu : function(){
34593 * Ext JS Library 1.1.1
34594 * Copyright(c) 2006-2007, Ext JS, LLC.
34596 * Originally Released Under LGPL - original licence link has changed is not relivant.
34599 * <script type="text/javascript">
34603 * @class Roo.menu.Adapter
34604 * @extends Roo.menu.BaseItem
34605 * 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.
34606 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34608 * Creates a new Adapter
34609 * @param {Object} config Configuration options
34611 Roo.menu.Adapter = function(component, config){
34612 Roo.menu.Adapter.superclass.constructor.call(this, config);
34613 this.component = component;
34615 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34617 canActivate : true,
34620 onRender : function(container, position){
34621 this.component.render(container);
34622 this.el = this.component.getEl();
34626 activate : function(){
34630 this.component.focus();
34631 this.fireEvent("activate", this);
34636 deactivate : function(){
34637 this.fireEvent("deactivate", this);
34641 disable : function(){
34642 this.component.disable();
34643 Roo.menu.Adapter.superclass.disable.call(this);
34647 enable : function(){
34648 this.component.enable();
34649 Roo.menu.Adapter.superclass.enable.call(this);
34653 * Ext JS Library 1.1.1
34654 * Copyright(c) 2006-2007, Ext JS, LLC.
34656 * Originally Released Under LGPL - original licence link has changed is not relivant.
34659 * <script type="text/javascript">
34663 * @class Roo.menu.TextItem
34664 * @extends Roo.menu.BaseItem
34665 * Adds a static text string to a menu, usually used as either a heading or group separator.
34666 * Note: old style constructor with text is still supported.
34669 * Creates a new TextItem
34670 * @param {Object} cfg Configuration
34672 Roo.menu.TextItem = function(cfg){
34673 if (typeof(cfg) == 'string') {
34676 Roo.apply(this,cfg);
34679 Roo.menu.TextItem.superclass.constructor.call(this);
34682 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34684 * @cfg {Boolean} text Text to show on item.
34689 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34691 hideOnClick : false,
34693 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34695 itemCls : "x-menu-text",
34698 onRender : function(){
34699 var s = document.createElement("span");
34700 s.className = this.itemCls;
34701 s.innerHTML = this.text;
34703 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34707 * Ext JS Library 1.1.1
34708 * Copyright(c) 2006-2007, Ext JS, LLC.
34710 * Originally Released Under LGPL - original licence link has changed is not relivant.
34713 * <script type="text/javascript">
34717 * @class Roo.menu.Separator
34718 * @extends Roo.menu.BaseItem
34719 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34720 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34722 * @param {Object} config Configuration options
34724 Roo.menu.Separator = function(config){
34725 Roo.menu.Separator.superclass.constructor.call(this, config);
34728 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34730 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34732 itemCls : "x-menu-sep",
34734 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34736 hideOnClick : false,
34739 onRender : function(li){
34740 var s = document.createElement("span");
34741 s.className = this.itemCls;
34742 s.innerHTML = " ";
34744 li.addClass("x-menu-sep-li");
34745 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34749 * Ext JS Library 1.1.1
34750 * Copyright(c) 2006-2007, Ext JS, LLC.
34752 * Originally Released Under LGPL - original licence link has changed is not relivant.
34755 * <script type="text/javascript">
34758 * @class Roo.menu.Item
34759 * @extends Roo.menu.BaseItem
34760 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34761 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34762 * activation and click handling.
34764 * Creates a new Item
34765 * @param {Object} config Configuration options
34767 Roo.menu.Item = function(config){
34768 Roo.menu.Item.superclass.constructor.call(this, config);
34770 this.menu = Roo.menu.MenuMgr.get(this.menu);
34773 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34776 * @cfg {String} text
34777 * The text to show on the menu item.
34781 * @cfg {String} HTML to render in menu
34782 * The text to show on the menu item (HTML version).
34786 * @cfg {String} icon
34787 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34791 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34793 itemCls : "x-menu-item",
34795 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34797 canActivate : true,
34799 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34802 // doc'd in BaseItem
34806 ctype: "Roo.menu.Item",
34809 onRender : function(container, position){
34810 var el = document.createElement("a");
34811 el.hideFocus = true;
34812 el.unselectable = "on";
34813 el.href = this.href || "#";
34814 if(this.hrefTarget){
34815 el.target = this.hrefTarget;
34817 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34819 var html = this.html.length ? this.html : String.format('{0}',this.text);
34821 el.innerHTML = String.format(
34822 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34823 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34825 Roo.menu.Item.superclass.onRender.call(this, container, position);
34829 * Sets the text to display in this menu item
34830 * @param {String} text The text to display
34831 * @param {Boolean} isHTML true to indicate text is pure html.
34833 setText : function(text, isHTML){
34841 var html = this.html.length ? this.html : String.format('{0}',this.text);
34843 this.el.update(String.format(
34844 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34845 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34846 this.parentMenu.autoWidth();
34851 handleClick : function(e){
34852 if(!this.href){ // if no link defined, stop the event automatically
34855 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34859 activate : function(autoExpand){
34860 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34870 shouldDeactivate : function(e){
34871 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34872 if(this.menu && this.menu.isVisible()){
34873 return !this.menu.getEl().getRegion().contains(e.getPoint());
34881 deactivate : function(){
34882 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34887 expandMenu : function(autoActivate){
34888 if(!this.disabled && this.menu){
34889 clearTimeout(this.hideTimer);
34890 delete this.hideTimer;
34891 if(!this.menu.isVisible() && !this.showTimer){
34892 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34893 }else if (this.menu.isVisible() && autoActivate){
34894 this.menu.tryActivate(0, 1);
34900 deferExpand : function(autoActivate){
34901 delete this.showTimer;
34902 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34904 this.menu.tryActivate(0, 1);
34909 hideMenu : function(){
34910 clearTimeout(this.showTimer);
34911 delete this.showTimer;
34912 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34913 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34918 deferHide : function(){
34919 delete this.hideTimer;
34924 * Ext JS Library 1.1.1
34925 * Copyright(c) 2006-2007, Ext JS, LLC.
34927 * Originally Released Under LGPL - original licence link has changed is not relivant.
34930 * <script type="text/javascript">
34934 * @class Roo.menu.CheckItem
34935 * @extends Roo.menu.Item
34936 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34938 * Creates a new CheckItem
34939 * @param {Object} config Configuration options
34941 Roo.menu.CheckItem = function(config){
34942 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34945 * @event beforecheckchange
34946 * Fires before the checked value is set, providing an opportunity to cancel if needed
34947 * @param {Roo.menu.CheckItem} this
34948 * @param {Boolean} checked The new checked value that will be set
34950 "beforecheckchange" : true,
34952 * @event checkchange
34953 * Fires after the checked value has been set
34954 * @param {Roo.menu.CheckItem} this
34955 * @param {Boolean} checked The checked value that was set
34957 "checkchange" : true
34959 if(this.checkHandler){
34960 this.on('checkchange', this.checkHandler, this.scope);
34963 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34965 * @cfg {String} group
34966 * All check items with the same group name will automatically be grouped into a single-select
34967 * radio button group (defaults to '')
34970 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34972 itemCls : "x-menu-item x-menu-check-item",
34974 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34976 groupClass : "x-menu-group-item",
34979 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34980 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34981 * initialized with checked = true will be rendered as checked.
34986 ctype: "Roo.menu.CheckItem",
34989 onRender : function(c){
34990 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34992 this.el.addClass(this.groupClass);
34994 Roo.menu.MenuMgr.registerCheckable(this);
34996 this.checked = false;
34997 this.setChecked(true, true);
35002 destroy : function(){
35004 Roo.menu.MenuMgr.unregisterCheckable(this);
35006 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35010 * Set the checked state of this item
35011 * @param {Boolean} checked The new checked value
35012 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35014 setChecked : function(state, suppressEvent){
35015 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35016 if(this.container){
35017 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35019 this.checked = state;
35020 if(suppressEvent !== true){
35021 this.fireEvent("checkchange", this, state);
35027 handleClick : function(e){
35028 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35029 this.setChecked(!this.checked);
35031 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35035 * Ext JS Library 1.1.1
35036 * Copyright(c) 2006-2007, Ext JS, LLC.
35038 * Originally Released Under LGPL - original licence link has changed is not relivant.
35041 * <script type="text/javascript">
35045 * @class Roo.menu.DateItem
35046 * @extends Roo.menu.Adapter
35047 * A menu item that wraps the {@link Roo.DatPicker} component.
35049 * Creates a new DateItem
35050 * @param {Object} config Configuration options
35052 Roo.menu.DateItem = function(config){
35053 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35054 /** The Roo.DatePicker object @type Roo.DatePicker */
35055 this.picker = this.component;
35056 this.addEvents({select: true});
35058 this.picker.on("render", function(picker){
35059 picker.getEl().swallowEvent("click");
35060 picker.container.addClass("x-menu-date-item");
35063 this.picker.on("select", this.onSelect, this);
35066 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35068 onSelect : function(picker, date){
35069 this.fireEvent("select", this, date, picker);
35070 Roo.menu.DateItem.superclass.handleClick.call(this);
35074 * Ext JS Library 1.1.1
35075 * Copyright(c) 2006-2007, Ext JS, LLC.
35077 * Originally Released Under LGPL - original licence link has changed is not relivant.
35080 * <script type="text/javascript">
35084 * @class Roo.menu.ColorItem
35085 * @extends Roo.menu.Adapter
35086 * A menu item that wraps the {@link Roo.ColorPalette} component.
35088 * Creates a new ColorItem
35089 * @param {Object} config Configuration options
35091 Roo.menu.ColorItem = function(config){
35092 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35093 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35094 this.palette = this.component;
35095 this.relayEvents(this.palette, ["select"]);
35096 if(this.selectHandler){
35097 this.on('select', this.selectHandler, this.scope);
35100 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35102 * Ext JS Library 1.1.1
35103 * Copyright(c) 2006-2007, Ext JS, LLC.
35105 * Originally Released Under LGPL - original licence link has changed is not relivant.
35108 * <script type="text/javascript">
35113 * @class Roo.menu.DateMenu
35114 * @extends Roo.menu.Menu
35115 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35117 * Creates a new DateMenu
35118 * @param {Object} config Configuration options
35120 Roo.menu.DateMenu = function(config){
35121 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35123 var di = new Roo.menu.DateItem(config);
35126 * The {@link Roo.DatePicker} instance for this DateMenu
35129 this.picker = di.picker;
35132 * @param {DatePicker} picker
35133 * @param {Date} date
35135 this.relayEvents(di, ["select"]);
35137 this.on('beforeshow', function(){
35139 this.picker.hideMonthPicker(true);
35143 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35147 * Ext JS Library 1.1.1
35148 * Copyright(c) 2006-2007, Ext JS, LLC.
35150 * Originally Released Under LGPL - original licence link has changed is not relivant.
35153 * <script type="text/javascript">
35158 * @class Roo.menu.ColorMenu
35159 * @extends Roo.menu.Menu
35160 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35162 * Creates a new ColorMenu
35163 * @param {Object} config Configuration options
35165 Roo.menu.ColorMenu = function(config){
35166 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35168 var ci = new Roo.menu.ColorItem(config);
35171 * The {@link Roo.ColorPalette} instance for this ColorMenu
35172 * @type ColorPalette
35174 this.palette = ci.palette;
35177 * @param {ColorPalette} palette
35178 * @param {String} color
35180 this.relayEvents(ci, ["select"]);
35182 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35184 * Ext JS Library 1.1.1
35185 * Copyright(c) 2006-2007, Ext JS, LLC.
35187 * Originally Released Under LGPL - original licence link has changed is not relivant.
35190 * <script type="text/javascript">
35194 * @class Roo.form.Field
35195 * @extends Roo.BoxComponent
35196 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35198 * Creates a new Field
35199 * @param {Object} config Configuration options
35201 Roo.form.Field = function(config){
35202 Roo.form.Field.superclass.constructor.call(this, config);
35205 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35207 * @cfg {String} fieldLabel Label to use when rendering a form.
35210 * @cfg {String} qtip Mouse over tip
35214 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35216 invalidClass : "x-form-invalid",
35218 * @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")
35220 invalidText : "The value in this field is invalid",
35222 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35224 focusClass : "x-form-focus",
35226 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35227 automatic validation (defaults to "keyup").
35229 validationEvent : "keyup",
35231 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35233 validateOnBlur : true,
35235 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35237 validationDelay : 250,
35239 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35240 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35242 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35244 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35246 fieldClass : "x-form-field",
35248 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35251 ----------- ----------------------------------------------------------------------
35252 qtip Display a quick tip when the user hovers over the field
35253 title Display a default browser title attribute popup
35254 under Add a block div beneath the field containing the error text
35255 side Add an error icon to the right of the field with a popup on hover
35256 [element id] Add the error text directly to the innerHTML of the specified element
35259 msgTarget : 'qtip',
35261 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35266 * @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.
35271 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35276 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35278 inputType : undefined,
35281 * @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).
35283 tabIndex : undefined,
35286 isFormField : true,
35291 * @property {Roo.Element} fieldEl
35292 * Element Containing the rendered Field (with label etc.)
35295 * @cfg {Mixed} value A value to initialize this field with.
35300 * @cfg {String} name The field's HTML name attribute.
35303 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35307 initComponent : function(){
35308 Roo.form.Field.superclass.initComponent.call(this);
35312 * Fires when this field receives input focus.
35313 * @param {Roo.form.Field} this
35318 * Fires when this field loses input focus.
35319 * @param {Roo.form.Field} this
35323 * @event specialkey
35324 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35325 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35326 * @param {Roo.form.Field} this
35327 * @param {Roo.EventObject} e The event object
35332 * Fires just before the field blurs if the field value has changed.
35333 * @param {Roo.form.Field} this
35334 * @param {Mixed} newValue The new value
35335 * @param {Mixed} oldValue The original value
35340 * Fires after the field has been marked as invalid.
35341 * @param {Roo.form.Field} this
35342 * @param {String} msg The validation message
35347 * Fires after the field has been validated with no errors.
35348 * @param {Roo.form.Field} this
35353 * Fires after the key up
35354 * @param {Roo.form.Field} this
35355 * @param {Roo.EventObject} e The event Object
35362 * Returns the name attribute of the field if available
35363 * @return {String} name The field name
35365 getName: function(){
35366 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35370 onRender : function(ct, position){
35371 Roo.form.Field.superclass.onRender.call(this, ct, position);
35373 var cfg = this.getAutoCreate();
35375 cfg.name = this.name || this.id;
35377 if(this.inputType){
35378 cfg.type = this.inputType;
35380 this.el = ct.createChild(cfg, position);
35382 var type = this.el.dom.type;
35384 if(type == 'password'){
35387 this.el.addClass('x-form-'+type);
35390 this.el.dom.readOnly = true;
35392 if(this.tabIndex !== undefined){
35393 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35396 this.el.addClass([this.fieldClass, this.cls]);
35401 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35402 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35403 * @return {Roo.form.Field} this
35405 applyTo : function(target){
35406 this.allowDomMove = false;
35407 this.el = Roo.get(target);
35408 this.render(this.el.dom.parentNode);
35413 initValue : function(){
35414 if(this.value !== undefined){
35415 this.setValue(this.value);
35416 }else if(this.el.dom.value.length > 0){
35417 this.setValue(this.el.dom.value);
35422 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35424 isDirty : function() {
35425 if(this.disabled) {
35428 return String(this.getValue()) !== String(this.originalValue);
35432 afterRender : function(){
35433 Roo.form.Field.superclass.afterRender.call(this);
35438 fireKey : function(e){
35439 //Roo.log('field ' + e.getKey());
35440 if(e.isNavKeyPress()){
35441 this.fireEvent("specialkey", this, e);
35446 * Resets the current field value to the originally loaded value and clears any validation messages
35448 reset : function(){
35449 this.setValue(this.originalValue);
35450 this.clearInvalid();
35454 initEvents : function(){
35455 // safari killled keypress - so keydown is now used..
35456 this.el.on("keydown" , this.fireKey, this);
35457 this.el.on("focus", this.onFocus, this);
35458 this.el.on("blur", this.onBlur, this);
35459 this.el.relayEvent('keyup', this);
35461 // reference to original value for reset
35462 this.originalValue = this.getValue();
35466 onFocus : function(){
35467 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35468 this.el.addClass(this.focusClass);
35470 if(!this.hasFocus){
35471 this.hasFocus = true;
35472 this.startValue = this.getValue();
35473 this.fireEvent("focus", this);
35477 beforeBlur : Roo.emptyFn,
35480 onBlur : function(){
35482 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35483 this.el.removeClass(this.focusClass);
35485 this.hasFocus = false;
35486 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35489 var v = this.getValue();
35490 if(String(v) !== String(this.startValue)){
35491 this.fireEvent('change', this, v, this.startValue);
35493 this.fireEvent("blur", this);
35497 * Returns whether or not the field value is currently valid
35498 * @param {Boolean} preventMark True to disable marking the field invalid
35499 * @return {Boolean} True if the value is valid, else false
35501 isValid : function(preventMark){
35505 var restore = this.preventMark;
35506 this.preventMark = preventMark === true;
35507 var v = this.validateValue(this.processValue(this.getRawValue()));
35508 this.preventMark = restore;
35513 * Validates the field value
35514 * @return {Boolean} True if the value is valid, else false
35516 validate : function(){
35517 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35518 this.clearInvalid();
35524 processValue : function(value){
35529 // Subclasses should provide the validation implementation by overriding this
35530 validateValue : function(value){
35535 * Mark this field as invalid
35536 * @param {String} msg The validation message
35538 markInvalid : function(msg){
35539 if(!this.rendered || this.preventMark){ // not rendered
35542 this.el.addClass(this.invalidClass);
35543 msg = msg || this.invalidText;
35544 switch(this.msgTarget){
35546 this.el.dom.qtip = msg;
35547 this.el.dom.qclass = 'x-form-invalid-tip';
35548 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35549 Roo.QuickTips.enable();
35553 this.el.dom.title = msg;
35557 var elp = this.el.findParent('.x-form-element', 5, true);
35558 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35559 this.errorEl.setWidth(elp.getWidth(true)-20);
35561 this.errorEl.update(msg);
35562 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35565 if(!this.errorIcon){
35566 var elp = this.el.findParent('.x-form-element', 5, true);
35567 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35569 this.alignErrorIcon();
35570 this.errorIcon.dom.qtip = msg;
35571 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35572 this.errorIcon.show();
35573 this.on('resize', this.alignErrorIcon, this);
35576 var t = Roo.getDom(this.msgTarget);
35578 t.style.display = this.msgDisplay;
35581 this.fireEvent('invalid', this, msg);
35585 alignErrorIcon : function(){
35586 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35590 * Clear any invalid styles/messages for this field
35592 clearInvalid : function(){
35593 if(!this.rendered || this.preventMark){ // not rendered
35596 this.el.removeClass(this.invalidClass);
35597 switch(this.msgTarget){
35599 this.el.dom.qtip = '';
35602 this.el.dom.title = '';
35606 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35610 if(this.errorIcon){
35611 this.errorIcon.dom.qtip = '';
35612 this.errorIcon.hide();
35613 this.un('resize', this.alignErrorIcon, this);
35617 var t = Roo.getDom(this.msgTarget);
35619 t.style.display = 'none';
35622 this.fireEvent('valid', this);
35626 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35627 * @return {Mixed} value The field value
35629 getRawValue : function(){
35630 var v = this.el.getValue();
35631 if(v === this.emptyText){
35638 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35639 * @return {Mixed} value The field value
35641 getValue : function(){
35642 var v = this.el.getValue();
35643 if(v === this.emptyText || v === undefined){
35650 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35651 * @param {Mixed} value The value to set
35653 setRawValue : function(v){
35654 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35658 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35659 * @param {Mixed} value The value to set
35661 setValue : function(v){
35664 this.el.dom.value = (v === null || v === undefined ? '' : v);
35669 adjustSize : function(w, h){
35670 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35671 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35675 adjustWidth : function(tag, w){
35676 tag = tag.toLowerCase();
35677 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35678 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35679 if(tag == 'input'){
35682 if(tag = 'textarea'){
35685 }else if(Roo.isOpera){
35686 if(tag == 'input'){
35689 if(tag = 'textarea'){
35699 // anything other than normal should be considered experimental
35700 Roo.form.Field.msgFx = {
35702 show: function(msgEl, f){
35703 msgEl.setDisplayed('block');
35706 hide : function(msgEl, f){
35707 msgEl.setDisplayed(false).update('');
35712 show: function(msgEl, f){
35713 msgEl.slideIn('t', {stopFx:true});
35716 hide : function(msgEl, f){
35717 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35722 show: function(msgEl, f){
35723 msgEl.fixDisplay();
35724 msgEl.alignTo(f.el, 'tl-tr');
35725 msgEl.slideIn('l', {stopFx:true});
35728 hide : function(msgEl, f){
35729 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35734 * Ext JS Library 1.1.1
35735 * Copyright(c) 2006-2007, Ext JS, LLC.
35737 * Originally Released Under LGPL - original licence link has changed is not relivant.
35740 * <script type="text/javascript">
35745 * @class Roo.form.TextField
35746 * @extends Roo.form.Field
35747 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35748 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35750 * Creates a new TextField
35751 * @param {Object} config Configuration options
35753 Roo.form.TextField = function(config){
35754 Roo.form.TextField.superclass.constructor.call(this, config);
35758 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35759 * according to the default logic, but this event provides a hook for the developer to apply additional
35760 * logic at runtime to resize the field if needed.
35761 * @param {Roo.form.Field} this This text field
35762 * @param {Number} width The new field width
35768 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35770 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35774 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35778 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35782 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35786 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35790 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35792 disableKeyFilter : false,
35794 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35798 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35802 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35804 maxLength : Number.MAX_VALUE,
35806 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35808 minLengthText : "The minimum length for this field is {0}",
35810 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35812 maxLengthText : "The maximum length for this field is {0}",
35814 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35816 selectOnFocus : false,
35818 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35820 blankText : "This field is required",
35822 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35823 * If available, this function will be called only after the basic validators all return true, and will be passed the
35824 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35828 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35829 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35830 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35834 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35838 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35842 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35843 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35845 emptyClass : 'x-form-empty-field',
35848 initEvents : function(){
35849 Roo.form.TextField.superclass.initEvents.call(this);
35850 if(this.validationEvent == 'keyup'){
35851 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35852 this.el.on('keyup', this.filterValidation, this);
35854 else if(this.validationEvent !== false){
35855 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35857 if(this.selectOnFocus || this.emptyText){
35858 this.on("focus", this.preFocus, this);
35859 if(this.emptyText){
35860 this.on('blur', this.postBlur, this);
35861 this.applyEmptyText();
35864 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35865 this.el.on("keypress", this.filterKeys, this);
35868 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35869 this.el.on("click", this.autoSize, this);
35873 processValue : function(value){
35874 if(this.stripCharsRe){
35875 var newValue = value.replace(this.stripCharsRe, '');
35876 if(newValue !== value){
35877 this.setRawValue(newValue);
35884 filterValidation : function(e){
35885 if(!e.isNavKeyPress()){
35886 this.validationTask.delay(this.validationDelay);
35891 onKeyUp : function(e){
35892 if(!e.isNavKeyPress()){
35898 * Resets the current field value to the originally-loaded value and clears any validation messages.
35899 * Also adds emptyText and emptyClass if the original value was blank.
35901 reset : function(){
35902 Roo.form.TextField.superclass.reset.call(this);
35903 this.applyEmptyText();
35906 applyEmptyText : function(){
35907 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35908 this.setRawValue(this.emptyText);
35909 this.el.addClass(this.emptyClass);
35914 preFocus : function(){
35915 if(this.emptyText){
35916 if(this.el.dom.value == this.emptyText){
35917 this.setRawValue('');
35919 this.el.removeClass(this.emptyClass);
35921 if(this.selectOnFocus){
35922 this.el.dom.select();
35927 postBlur : function(){
35928 this.applyEmptyText();
35932 filterKeys : function(e){
35933 var k = e.getKey();
35934 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35937 var c = e.getCharCode(), cc = String.fromCharCode(c);
35938 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35941 if(!this.maskRe.test(cc)){
35946 setValue : function(v){
35947 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35948 this.el.removeClass(this.emptyClass);
35950 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35951 this.applyEmptyText();
35956 * Validates a value according to the field's validation rules and marks the field as invalid
35957 * if the validation fails
35958 * @param {Mixed} value The value to validate
35959 * @return {Boolean} True if the value is valid, else false
35961 validateValue : function(value){
35962 if(value.length < 1 || value === this.emptyText){ // if it's blank
35963 if(this.allowBlank){
35964 this.clearInvalid();
35967 this.markInvalid(this.blankText);
35971 if(value.length < this.minLength){
35972 this.markInvalid(String.format(this.minLengthText, this.minLength));
35975 if(value.length > this.maxLength){
35976 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35980 var vt = Roo.form.VTypes;
35981 if(!vt[this.vtype](value, this)){
35982 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35986 if(typeof this.validator == "function"){
35987 var msg = this.validator(value);
35989 this.markInvalid(msg);
35993 if(this.regex && !this.regex.test(value)){
35994 this.markInvalid(this.regexText);
36001 * Selects text in this field
36002 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36003 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36005 selectText : function(start, end){
36006 var v = this.getRawValue();
36008 start = start === undefined ? 0 : start;
36009 end = end === undefined ? v.length : end;
36010 var d = this.el.dom;
36011 if(d.setSelectionRange){
36012 d.setSelectionRange(start, end);
36013 }else if(d.createTextRange){
36014 var range = d.createTextRange();
36015 range.moveStart("character", start);
36016 range.moveEnd("character", v.length-end);
36023 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36024 * This only takes effect if grow = true, and fires the autosize event.
36026 autoSize : function(){
36027 if(!this.grow || !this.rendered){
36031 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36034 var v = el.dom.value;
36035 var d = document.createElement('div');
36036 d.appendChild(document.createTextNode(v));
36040 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36041 this.el.setWidth(w);
36042 this.fireEvent("autosize", this, w);
36046 * Ext JS Library 1.1.1
36047 * Copyright(c) 2006-2007, Ext JS, LLC.
36049 * Originally Released Under LGPL - original licence link has changed is not relivant.
36052 * <script type="text/javascript">
36056 * @class Roo.form.Hidden
36057 * @extends Roo.form.TextField
36058 * Simple Hidden element used on forms
36060 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36063 * Creates a new Hidden form element.
36064 * @param {Object} config Configuration options
36069 // easy hidden field...
36070 Roo.form.Hidden = function(config){
36071 Roo.form.Hidden.superclass.constructor.call(this, config);
36074 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36076 inputType: 'hidden',
36079 labelSeparator: '',
36081 itemCls : 'x-form-item-display-none'
36089 * Ext JS Library 1.1.1
36090 * Copyright(c) 2006-2007, Ext JS, LLC.
36092 * Originally Released Under LGPL - original licence link has changed is not relivant.
36095 * <script type="text/javascript">
36099 * @class Roo.form.TriggerField
36100 * @extends Roo.form.TextField
36101 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36102 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36103 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36104 * for which you can provide a custom implementation. For example:
36106 var trigger = new Roo.form.TriggerField();
36107 trigger.onTriggerClick = myTriggerFn;
36108 trigger.applyTo('my-field');
36111 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36112 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36113 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36114 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36116 * Create a new TriggerField.
36117 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36118 * to the base TextField)
36120 Roo.form.TriggerField = function(config){
36121 this.mimicing = false;
36122 Roo.form.TriggerField.superclass.constructor.call(this, config);
36125 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36127 * @cfg {String} triggerClass A CSS class to apply to the trigger
36130 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36131 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36133 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36135 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36139 /** @cfg {Boolean} grow @hide */
36140 /** @cfg {Number} growMin @hide */
36141 /** @cfg {Number} growMax @hide */
36147 autoSize: Roo.emptyFn,
36151 deferHeight : true,
36154 actionMode : 'wrap',
36156 onResize : function(w, h){
36157 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36158 if(typeof w == 'number'){
36159 var x = w - this.trigger.getWidth();
36160 this.el.setWidth(this.adjustWidth('input', x));
36161 this.trigger.setStyle('left', x+'px');
36166 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36169 getResizeEl : function(){
36174 getPositionEl : function(){
36179 alignErrorIcon : function(){
36180 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36184 onRender : function(ct, position){
36185 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36186 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36187 this.trigger = this.wrap.createChild(this.triggerConfig ||
36188 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36189 if(this.hideTrigger){
36190 this.trigger.setDisplayed(false);
36192 this.initTrigger();
36194 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36199 initTrigger : function(){
36200 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36201 this.trigger.addClassOnOver('x-form-trigger-over');
36202 this.trigger.addClassOnClick('x-form-trigger-click');
36206 onDestroy : function(){
36208 this.trigger.removeAllListeners();
36209 this.trigger.remove();
36212 this.wrap.remove();
36214 Roo.form.TriggerField.superclass.onDestroy.call(this);
36218 onFocus : function(){
36219 Roo.form.TriggerField.superclass.onFocus.call(this);
36220 if(!this.mimicing){
36221 this.wrap.addClass('x-trigger-wrap-focus');
36222 this.mimicing = true;
36223 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36224 if(this.monitorTab){
36225 this.el.on("keydown", this.checkTab, this);
36231 checkTab : function(e){
36232 if(e.getKey() == e.TAB){
36233 this.triggerBlur();
36238 onBlur : function(){
36243 mimicBlur : function(e, t){
36244 if(!this.wrap.contains(t) && this.validateBlur()){
36245 this.triggerBlur();
36250 triggerBlur : function(){
36251 this.mimicing = false;
36252 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36253 if(this.monitorTab){
36254 this.el.un("keydown", this.checkTab, this);
36256 this.wrap.removeClass('x-trigger-wrap-focus');
36257 Roo.form.TriggerField.superclass.onBlur.call(this);
36261 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36262 validateBlur : function(e, t){
36267 onDisable : function(){
36268 Roo.form.TriggerField.superclass.onDisable.call(this);
36270 this.wrap.addClass('x-item-disabled');
36275 onEnable : function(){
36276 Roo.form.TriggerField.superclass.onEnable.call(this);
36278 this.wrap.removeClass('x-item-disabled');
36283 onShow : function(){
36284 var ae = this.getActionEl();
36287 ae.dom.style.display = '';
36288 ae.dom.style.visibility = 'visible';
36294 onHide : function(){
36295 var ae = this.getActionEl();
36296 ae.dom.style.display = 'none';
36300 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36301 * by an implementing function.
36303 * @param {EventObject} e
36305 onTriggerClick : Roo.emptyFn
36308 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36309 // to be extended by an implementing class. For an example of implementing this class, see the custom
36310 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36311 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36312 initComponent : function(){
36313 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36315 this.triggerConfig = {
36316 tag:'span', cls:'x-form-twin-triggers', cn:[
36317 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36318 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36322 getTrigger : function(index){
36323 return this.triggers[index];
36326 initTrigger : function(){
36327 var ts = this.trigger.select('.x-form-trigger', true);
36328 this.wrap.setStyle('overflow', 'hidden');
36329 var triggerField = this;
36330 ts.each(function(t, all, index){
36331 t.hide = function(){
36332 var w = triggerField.wrap.getWidth();
36333 this.dom.style.display = 'none';
36334 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36336 t.show = function(){
36337 var w = triggerField.wrap.getWidth();
36338 this.dom.style.display = '';
36339 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36341 var triggerIndex = 'Trigger'+(index+1);
36343 if(this['hide'+triggerIndex]){
36344 t.dom.style.display = 'none';
36346 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36347 t.addClassOnOver('x-form-trigger-over');
36348 t.addClassOnClick('x-form-trigger-click');
36350 this.triggers = ts.elements;
36353 onTrigger1Click : Roo.emptyFn,
36354 onTrigger2Click : Roo.emptyFn
36357 * Ext JS Library 1.1.1
36358 * Copyright(c) 2006-2007, Ext JS, LLC.
36360 * Originally Released Under LGPL - original licence link has changed is not relivant.
36363 * <script type="text/javascript">
36367 * @class Roo.form.TextArea
36368 * @extends Roo.form.TextField
36369 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36370 * support for auto-sizing.
36372 * Creates a new TextArea
36373 * @param {Object} config Configuration options
36375 Roo.form.TextArea = function(config){
36376 Roo.form.TextArea.superclass.constructor.call(this, config);
36377 // these are provided exchanges for backwards compat
36378 // minHeight/maxHeight were replaced by growMin/growMax to be
36379 // compatible with TextField growing config values
36380 if(this.minHeight !== undefined){
36381 this.growMin = this.minHeight;
36383 if(this.maxHeight !== undefined){
36384 this.growMax = this.maxHeight;
36388 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36390 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36394 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36398 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36399 * in the field (equivalent to setting overflow: hidden, defaults to false)
36401 preventScrollbars: false,
36403 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36404 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36408 onRender : function(ct, position){
36410 this.defaultAutoCreate = {
36412 style:"width:300px;height:60px;",
36413 autocomplete: "off"
36416 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36418 this.textSizeEl = Roo.DomHelper.append(document.body, {
36419 tag: "pre", cls: "x-form-grow-sizer"
36421 if(this.preventScrollbars){
36422 this.el.setStyle("overflow", "hidden");
36424 this.el.setHeight(this.growMin);
36428 onDestroy : function(){
36429 if(this.textSizeEl){
36430 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36432 Roo.form.TextArea.superclass.onDestroy.call(this);
36436 onKeyUp : function(e){
36437 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36443 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36444 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36446 autoSize : function(){
36447 if(!this.grow || !this.textSizeEl){
36451 var v = el.dom.value;
36452 var ts = this.textSizeEl;
36455 ts.appendChild(document.createTextNode(v));
36458 Roo.fly(ts).setWidth(this.el.getWidth());
36460 v = "  ";
36463 v = v.replace(/\n/g, '<p> </p>');
36465 v += " \n ";
36468 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36469 if(h != this.lastHeight){
36470 this.lastHeight = h;
36471 this.el.setHeight(h);
36472 this.fireEvent("autosize", this, h);
36477 * Ext JS Library 1.1.1
36478 * Copyright(c) 2006-2007, Ext JS, LLC.
36480 * Originally Released Under LGPL - original licence link has changed is not relivant.
36483 * <script type="text/javascript">
36488 * @class Roo.form.NumberField
36489 * @extends Roo.form.TextField
36490 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36492 * Creates a new NumberField
36493 * @param {Object} config Configuration options
36495 Roo.form.NumberField = function(config){
36496 Roo.form.NumberField.superclass.constructor.call(this, config);
36499 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36501 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36503 fieldClass: "x-form-field x-form-num-field",
36505 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36507 allowDecimals : true,
36509 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36511 decimalSeparator : ".",
36513 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36515 decimalPrecision : 2,
36517 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36519 allowNegative : true,
36521 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36523 minValue : Number.NEGATIVE_INFINITY,
36525 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36527 maxValue : Number.MAX_VALUE,
36529 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36531 minText : "The minimum value for this field is {0}",
36533 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36535 maxText : "The maximum value for this field is {0}",
36537 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36538 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36540 nanText : "{0} is not a valid number",
36543 initEvents : function(){
36544 Roo.form.NumberField.superclass.initEvents.call(this);
36545 var allowed = "0123456789";
36546 if(this.allowDecimals){
36547 allowed += this.decimalSeparator;
36549 if(this.allowNegative){
36552 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36553 var keyPress = function(e){
36554 var k = e.getKey();
36555 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36558 var c = e.getCharCode();
36559 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36563 this.el.on("keypress", keyPress, this);
36567 validateValue : function(value){
36568 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36571 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36574 var num = this.parseValue(value);
36576 this.markInvalid(String.format(this.nanText, value));
36579 if(num < this.minValue){
36580 this.markInvalid(String.format(this.minText, this.minValue));
36583 if(num > this.maxValue){
36584 this.markInvalid(String.format(this.maxText, this.maxValue));
36590 getValue : function(){
36591 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36595 parseValue : function(value){
36596 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36597 return isNaN(value) ? '' : value;
36601 fixPrecision : function(value){
36602 var nan = isNaN(value);
36603 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36604 return nan ? '' : value;
36606 return parseFloat(value).toFixed(this.decimalPrecision);
36609 setValue : function(v){
36610 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36614 decimalPrecisionFcn : function(v){
36615 return Math.floor(v);
36618 beforeBlur : function(){
36619 var v = this.parseValue(this.getRawValue());
36621 this.setValue(this.fixPrecision(v));
36626 * Ext JS Library 1.1.1
36627 * Copyright(c) 2006-2007, Ext JS, LLC.
36629 * Originally Released Under LGPL - original licence link has changed is not relivant.
36632 * <script type="text/javascript">
36636 * @class Roo.form.DateField
36637 * @extends Roo.form.TriggerField
36638 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36640 * Create a new DateField
36641 * @param {Object} config
36643 Roo.form.DateField = function(config){
36644 Roo.form.DateField.superclass.constructor.call(this, config);
36650 * Fires when a date is selected
36651 * @param {Roo.form.DateField} combo This combo box
36652 * @param {Date} date The date selected
36659 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36660 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36661 this.ddMatch = null;
36662 if(this.disabledDates){
36663 var dd = this.disabledDates;
36665 for(var i = 0; i < dd.length; i++){
36667 if(i != dd.length-1) re += "|";
36669 this.ddMatch = new RegExp(re + ")");
36673 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36675 * @cfg {String} format
36676 * The default date format string which can be overriden for localization support. The format must be
36677 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36681 * @cfg {String} altFormats
36682 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36683 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36685 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36687 * @cfg {Array} disabledDays
36688 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36690 disabledDays : null,
36692 * @cfg {String} disabledDaysText
36693 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36695 disabledDaysText : "Disabled",
36697 * @cfg {Array} disabledDates
36698 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36699 * expression so they are very powerful. Some examples:
36701 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36702 * <li>["03/08", "09/16"] would disable those days for every year</li>
36703 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36704 * <li>["03/../2006"] would disable every day in March 2006</li>
36705 * <li>["^03"] would disable every day in every March</li>
36707 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36708 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36710 disabledDates : null,
36712 * @cfg {String} disabledDatesText
36713 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36715 disabledDatesText : "Disabled",
36717 * @cfg {Date/String} minValue
36718 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36719 * valid format (defaults to null).
36723 * @cfg {Date/String} maxValue
36724 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36725 * valid format (defaults to null).
36729 * @cfg {String} minText
36730 * The error text to display when the date in the cell is before minValue (defaults to
36731 * 'The date in this field must be after {minValue}').
36733 minText : "The date in this field must be equal to or after {0}",
36735 * @cfg {String} maxText
36736 * The error text to display when the date in the cell is after maxValue (defaults to
36737 * 'The date in this field must be before {maxValue}').
36739 maxText : "The date in this field must be equal to or before {0}",
36741 * @cfg {String} invalidText
36742 * The error text to display when the date in the field is invalid (defaults to
36743 * '{value} is not a valid date - it must be in the format {format}').
36745 invalidText : "{0} is not a valid date - it must be in the format {1}",
36747 * @cfg {String} triggerClass
36748 * An additional CSS class used to style the trigger button. The trigger will always get the
36749 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36750 * which displays a calendar icon).
36752 triggerClass : 'x-form-date-trigger',
36756 * @cfg {bool} useIso
36757 * if enabled, then the date field will use a hidden field to store the
36758 * real value as iso formated date. default (false)
36762 * @cfg {String/Object} autoCreate
36763 * A DomHelper element spec, or true for a default element spec (defaults to
36764 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36767 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36770 hiddenField: false,
36772 onRender : function(ct, position)
36774 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36776 this.el.dom.removeAttribute('name');
36777 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36779 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36780 // prevent input submission
36781 this.hiddenName = this.name;
36788 validateValue : function(value)
36790 value = this.formatDate(value);
36791 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36794 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36797 var svalue = value;
36798 value = this.parseDate(value);
36800 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36803 var time = value.getTime();
36804 if(this.minValue && time < this.minValue.getTime()){
36805 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36808 if(this.maxValue && time > this.maxValue.getTime()){
36809 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36812 if(this.disabledDays){
36813 var day = value.getDay();
36814 for(var i = 0; i < this.disabledDays.length; i++) {
36815 if(day === this.disabledDays[i]){
36816 this.markInvalid(this.disabledDaysText);
36821 var fvalue = this.formatDate(value);
36822 if(this.ddMatch && this.ddMatch.test(fvalue)){
36823 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36830 // Provides logic to override the default TriggerField.validateBlur which just returns true
36831 validateBlur : function(){
36832 return !this.menu || !this.menu.isVisible();
36836 * Returns the current date value of the date field.
36837 * @return {Date} The date value
36839 getValue : function(){
36841 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36845 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36846 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36847 * (the default format used is "m/d/y").
36850 //All of these calls set the same date value (May 4, 2006)
36852 //Pass a date object:
36853 var dt = new Date('5/4/06');
36854 dateField.setValue(dt);
36856 //Pass a date string (default format):
36857 dateField.setValue('5/4/06');
36859 //Pass a date string (custom format):
36860 dateField.format = 'Y-m-d';
36861 dateField.setValue('2006-5-4');
36863 * @param {String/Date} date The date or valid date string
36865 setValue : function(date){
36866 if (this.hiddenField) {
36867 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36869 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36873 parseDate : function(value){
36874 if(!value || value instanceof Date){
36877 var v = Date.parseDate(value, this.format);
36878 if(!v && this.altFormats){
36879 if(!this.altFormatsArray){
36880 this.altFormatsArray = this.altFormats.split("|");
36882 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36883 v = Date.parseDate(value, this.altFormatsArray[i]);
36890 formatDate : function(date, fmt){
36891 return (!date || !(date instanceof Date)) ?
36892 date : date.dateFormat(fmt || this.format);
36897 select: function(m, d){
36899 this.fireEvent('select', this, d);
36901 show : function(){ // retain focus styling
36905 this.focus.defer(10, this);
36906 var ml = this.menuListeners;
36907 this.menu.un("select", ml.select, this);
36908 this.menu.un("show", ml.show, this);
36909 this.menu.un("hide", ml.hide, this);
36914 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36915 onTriggerClick : function(){
36919 if(this.menu == null){
36920 this.menu = new Roo.menu.DateMenu();
36922 Roo.apply(this.menu.picker, {
36923 showClear: this.allowBlank,
36924 minDate : this.minValue,
36925 maxDate : this.maxValue,
36926 disabledDatesRE : this.ddMatch,
36927 disabledDatesText : this.disabledDatesText,
36928 disabledDays : this.disabledDays,
36929 disabledDaysText : this.disabledDaysText,
36930 format : this.format,
36931 minText : String.format(this.minText, this.formatDate(this.minValue)),
36932 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36934 this.menu.on(Roo.apply({}, this.menuListeners, {
36937 this.menu.picker.setValue(this.getValue() || new Date());
36938 this.menu.show(this.el, "tl-bl?");
36941 beforeBlur : function(){
36942 var v = this.parseDate(this.getRawValue());
36948 /** @cfg {Boolean} grow @hide */
36949 /** @cfg {Number} growMin @hide */
36950 /** @cfg {Number} growMax @hide */
36957 * Ext JS Library 1.1.1
36958 * Copyright(c) 2006-2007, Ext JS, LLC.
36960 * Originally Released Under LGPL - original licence link has changed is not relivant.
36963 * <script type="text/javascript">
36968 * @class Roo.form.ComboBox
36969 * @extends Roo.form.TriggerField
36970 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36972 * Create a new ComboBox.
36973 * @param {Object} config Configuration options
36975 Roo.form.ComboBox = function(config){
36976 Roo.form.ComboBox.superclass.constructor.call(this, config);
36980 * Fires when the dropdown list is expanded
36981 * @param {Roo.form.ComboBox} combo This combo box
36986 * Fires when the dropdown list is collapsed
36987 * @param {Roo.form.ComboBox} combo This combo box
36991 * @event beforeselect
36992 * Fires before a list item is selected. Return false to cancel the selection.
36993 * @param {Roo.form.ComboBox} combo This combo box
36994 * @param {Roo.data.Record} record The data record returned from the underlying store
36995 * @param {Number} index The index of the selected item in the dropdown list
36997 'beforeselect' : true,
37000 * Fires when a list item is selected
37001 * @param {Roo.form.ComboBox} combo This combo box
37002 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37003 * @param {Number} index The index of the selected item in the dropdown list
37007 * @event beforequery
37008 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37009 * The event object passed has these properties:
37010 * @param {Roo.form.ComboBox} combo This combo box
37011 * @param {String} query The query
37012 * @param {Boolean} forceAll true to force "all" query
37013 * @param {Boolean} cancel true to cancel the query
37014 * @param {Object} e The query event object
37016 'beforequery': true,
37019 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37020 * @param {Roo.form.ComboBox} combo This combo box
37025 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37026 * @param {Roo.form.ComboBox} combo This combo box
37027 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37033 if(this.transform){
37034 this.allowDomMove = false;
37035 var s = Roo.getDom(this.transform);
37036 if(!this.hiddenName){
37037 this.hiddenName = s.name;
37040 this.mode = 'local';
37041 var d = [], opts = s.options;
37042 for(var i = 0, len = opts.length;i < len; i++){
37044 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37046 this.value = value;
37048 d.push([value, o.text]);
37050 this.store = new Roo.data.SimpleStore({
37052 fields: ['value', 'text'],
37055 this.valueField = 'value';
37056 this.displayField = 'text';
37058 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37059 if(!this.lazyRender){
37060 this.target = true;
37061 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37062 s.parentNode.removeChild(s); // remove it
37063 this.render(this.el.parentNode);
37065 s.parentNode.removeChild(s); // remove it
37070 this.store = Roo.factory(this.store, Roo.data);
37073 this.selectedIndex = -1;
37074 if(this.mode == 'local'){
37075 if(config.queryDelay === undefined){
37076 this.queryDelay = 10;
37078 if(config.minChars === undefined){
37084 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37086 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37089 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37090 * rendering into an Roo.Editor, defaults to false)
37093 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37094 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37097 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37100 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37101 * the dropdown list (defaults to undefined, with no header element)
37105 * @cfg {String/Roo.Template} tpl The template to use to render the output
37109 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37111 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37113 listWidth: undefined,
37115 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37116 * mode = 'remote' or 'text' if mode = 'local')
37118 displayField: undefined,
37120 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37121 * mode = 'remote' or 'value' if mode = 'local').
37122 * Note: use of a valueField requires the user make a selection
37123 * in order for a value to be mapped.
37125 valueField: undefined,
37127 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37128 * field's data value (defaults to the underlying DOM element's name)
37130 hiddenName: undefined,
37132 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37136 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37138 selectedClass: 'x-combo-selected',
37140 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37141 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37142 * which displays a downward arrow icon).
37144 triggerClass : 'x-form-arrow-trigger',
37146 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37150 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37151 * anchor positions (defaults to 'tl-bl')
37153 listAlign: 'tl-bl?',
37155 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37159 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37160 * query specified by the allQuery config option (defaults to 'query')
37162 triggerAction: 'query',
37164 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37165 * (defaults to 4, does not apply if editable = false)
37169 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37170 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37174 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37175 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37179 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37180 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37184 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37185 * when editable = true (defaults to false)
37187 selectOnFocus:false,
37189 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37191 queryParam: 'query',
37193 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37194 * when mode = 'remote' (defaults to 'Loading...')
37196 loadingText: 'Loading...',
37198 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37202 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37206 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37207 * traditional select (defaults to true)
37211 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37215 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37219 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37220 * listWidth has a higher value)
37224 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37225 * allow the user to set arbitrary text into the field (defaults to false)
37227 forceSelection:false,
37229 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37230 * if typeAhead = true (defaults to 250)
37232 typeAheadDelay : 250,
37234 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37235 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37237 valueNotFoundText : undefined,
37239 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37241 blockFocus : false,
37244 * @cfg {Boolean} disableClear Disable showing of clear button.
37246 disableClear : false,
37248 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37250 alwaysQuery : false,
37258 onRender : function(ct, position){
37259 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37260 if(this.hiddenName){
37261 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37263 this.hiddenField.value =
37264 this.hiddenValue !== undefined ? this.hiddenValue :
37265 this.value !== undefined ? this.value : '';
37267 // prevent input submission
37268 this.el.dom.removeAttribute('name');
37271 this.el.dom.setAttribute('autocomplete', 'off');
37274 var cls = 'x-combo-list';
37276 this.list = new Roo.Layer({
37277 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37280 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37281 this.list.setWidth(lw);
37282 this.list.swallowEvent('mousewheel');
37283 this.assetHeight = 0;
37286 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37287 this.assetHeight += this.header.getHeight();
37290 this.innerList = this.list.createChild({cls:cls+'-inner'});
37291 this.innerList.on('mouseover', this.onViewOver, this);
37292 this.innerList.on('mousemove', this.onViewMove, this);
37293 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37295 if(this.allowBlank && !this.pageSize && !this.disableClear){
37296 this.footer = this.list.createChild({cls:cls+'-ft'});
37297 this.pageTb = new Roo.Toolbar(this.footer);
37301 this.footer = this.list.createChild({cls:cls+'-ft'});
37302 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37303 {pageSize: this.pageSize});
37307 if (this.pageTb && this.allowBlank && !this.disableClear) {
37309 this.pageTb.add(new Roo.Toolbar.Fill(), {
37310 cls: 'x-btn-icon x-btn-clear',
37312 handler: function()
37315 _this.clearValue();
37316 _this.onSelect(false, -1);
37321 this.assetHeight += this.footer.getHeight();
37326 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37329 this.view = new Roo.View(this.innerList, this.tpl, {
37330 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37333 this.view.on('click', this.onViewClick, this);
37335 this.store.on('beforeload', this.onBeforeLoad, this);
37336 this.store.on('load', this.onLoad, this);
37337 this.store.on('loadexception', this.collapse, this);
37339 if(this.resizable){
37340 this.resizer = new Roo.Resizable(this.list, {
37341 pinned:true, handles:'se'
37343 this.resizer.on('resize', function(r, w, h){
37344 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37345 this.listWidth = w;
37346 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37347 this.restrictHeight();
37349 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37351 if(!this.editable){
37352 this.editable = true;
37353 this.setEditable(false);
37357 if (typeof(this.events.add.listeners) != 'undefined') {
37359 this.addicon = this.wrap.createChild(
37360 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37362 this.addicon.on('click', function(e) {
37363 this.fireEvent('add', this);
37366 if (typeof(this.events.edit.listeners) != 'undefined') {
37368 this.editicon = this.wrap.createChild(
37369 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37370 if (this.addicon) {
37371 this.editicon.setStyle('margin-left', '40px');
37373 this.editicon.on('click', function(e) {
37375 // we fire even if inothing is selected..
37376 this.fireEvent('edit', this, this.lastData );
37386 initEvents : function(){
37387 Roo.form.ComboBox.superclass.initEvents.call(this);
37389 this.keyNav = new Roo.KeyNav(this.el, {
37390 "up" : function(e){
37391 this.inKeyMode = true;
37395 "down" : function(e){
37396 if(!this.isExpanded()){
37397 this.onTriggerClick();
37399 this.inKeyMode = true;
37404 "enter" : function(e){
37405 this.onViewClick();
37409 "esc" : function(e){
37413 "tab" : function(e){
37414 this.onViewClick(false);
37420 doRelay : function(foo, bar, hname){
37421 if(hname == 'down' || this.scope.isExpanded()){
37422 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37429 this.queryDelay = Math.max(this.queryDelay || 10,
37430 this.mode == 'local' ? 10 : 250);
37431 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37432 if(this.typeAhead){
37433 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37435 if(this.editable !== false){
37436 this.el.on("keyup", this.onKeyUp, this);
37438 if(this.forceSelection){
37439 this.on('blur', this.doForce, this);
37443 onDestroy : function(){
37445 this.view.setStore(null);
37446 this.view.el.removeAllListeners();
37447 this.view.el.remove();
37448 this.view.purgeListeners();
37451 this.list.destroy();
37454 this.store.un('beforeload', this.onBeforeLoad, this);
37455 this.store.un('load', this.onLoad, this);
37456 this.store.un('loadexception', this.collapse, this);
37458 Roo.form.ComboBox.superclass.onDestroy.call(this);
37462 fireKey : function(e){
37463 if(e.isNavKeyPress() && !this.list.isVisible()){
37464 this.fireEvent("specialkey", this, e);
37469 onResize: function(w, h){
37470 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37472 if(typeof w != 'number'){
37473 // we do not handle it!?!?
37476 var tw = this.trigger.getWidth();
37477 tw += this.addicon ? this.addicon.getWidth() : 0;
37478 tw += this.editicon ? this.editicon.getWidth() : 0;
37480 this.el.setWidth( this.adjustWidth('input', x));
37482 this.trigger.setStyle('left', x+'px');
37484 if(this.list && this.listWidth === undefined){
37485 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37486 this.list.setWidth(lw);
37487 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37495 * Allow or prevent the user from directly editing the field text. If false is passed,
37496 * the user will only be able to select from the items defined in the dropdown list. This method
37497 * is the runtime equivalent of setting the 'editable' config option at config time.
37498 * @param {Boolean} value True to allow the user to directly edit the field text
37500 setEditable : function(value){
37501 if(value == this.editable){
37504 this.editable = value;
37506 this.el.dom.setAttribute('readOnly', true);
37507 this.el.on('mousedown', this.onTriggerClick, this);
37508 this.el.addClass('x-combo-noedit');
37510 this.el.dom.setAttribute('readOnly', false);
37511 this.el.un('mousedown', this.onTriggerClick, this);
37512 this.el.removeClass('x-combo-noedit');
37517 onBeforeLoad : function(){
37518 if(!this.hasFocus){
37521 this.innerList.update(this.loadingText ?
37522 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37523 this.restrictHeight();
37524 this.selectedIndex = -1;
37528 onLoad : function(){
37529 if(!this.hasFocus){
37532 if(this.store.getCount() > 0){
37534 this.restrictHeight();
37535 if(this.lastQuery == this.allQuery){
37537 this.el.dom.select();
37539 if(!this.selectByValue(this.value, true)){
37540 this.select(0, true);
37544 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37545 this.taTask.delay(this.typeAheadDelay);
37549 this.onEmptyResults();
37555 onTypeAhead : function(){
37556 if(this.store.getCount() > 0){
37557 var r = this.store.getAt(0);
37558 var newValue = r.data[this.displayField];
37559 var len = newValue.length;
37560 var selStart = this.getRawValue().length;
37561 if(selStart != len){
37562 this.setRawValue(newValue);
37563 this.selectText(selStart, newValue.length);
37569 onSelect : function(record, index){
37570 if(this.fireEvent('beforeselect', this, record, index) !== false){
37571 this.setFromData(index > -1 ? record.data : false);
37573 this.fireEvent('select', this, record, index);
37578 * Returns the currently selected field value or empty string if no value is set.
37579 * @return {String} value The selected value
37581 getValue : function(){
37582 if(this.valueField){
37583 return typeof this.value != 'undefined' ? this.value : '';
37585 return Roo.form.ComboBox.superclass.getValue.call(this);
37590 * Clears any text/value currently set in the field
37592 clearValue : function(){
37593 if(this.hiddenField){
37594 this.hiddenField.value = '';
37597 this.setRawValue('');
37598 this.lastSelectionText = '';
37599 this.applyEmptyText();
37603 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37604 * will be displayed in the field. If the value does not match the data value of an existing item,
37605 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37606 * Otherwise the field will be blank (although the value will still be set).
37607 * @param {String} value The value to match
37609 setValue : function(v){
37611 if(this.valueField){
37612 var r = this.findRecord(this.valueField, v);
37614 text = r.data[this.displayField];
37615 }else if(this.valueNotFoundText !== undefined){
37616 text = this.valueNotFoundText;
37619 this.lastSelectionText = text;
37620 if(this.hiddenField){
37621 this.hiddenField.value = v;
37623 Roo.form.ComboBox.superclass.setValue.call(this, text);
37627 * @property {Object} the last set data for the element
37632 * Sets the value of the field based on a object which is related to the record format for the store.
37633 * @param {Object} value the value to set as. or false on reset?
37635 setFromData : function(o){
37636 var dv = ''; // display value
37637 var vv = ''; // value value..
37639 if (this.displayField) {
37640 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37642 // this is an error condition!!!
37643 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37646 if(this.valueField){
37647 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37649 if(this.hiddenField){
37650 this.hiddenField.value = vv;
37652 this.lastSelectionText = dv;
37653 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37657 // no hidden field.. - we store the value in 'value', but still display
37658 // display field!!!!
37659 this.lastSelectionText = dv;
37660 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37666 reset : function(){
37667 // overridden so that last data is reset..
37668 this.setValue(this.originalValue);
37669 this.clearInvalid();
37670 this.lastData = false;
37673 findRecord : function(prop, value){
37675 if(this.store.getCount() > 0){
37676 this.store.each(function(r){
37677 if(r.data[prop] == value){
37687 onViewMove : function(e, t){
37688 this.inKeyMode = false;
37692 onViewOver : function(e, t){
37693 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37696 var item = this.view.findItemFromChild(t);
37698 var index = this.view.indexOf(item);
37699 this.select(index, false);
37704 onViewClick : function(doFocus){
37705 var index = this.view.getSelectedIndexes()[0];
37706 var r = this.store.getAt(index);
37708 this.onSelect(r, index);
37710 if(doFocus !== false && !this.blockFocus){
37716 restrictHeight : function(){
37717 this.innerList.dom.style.height = '';
37718 var inner = this.innerList.dom;
37719 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37720 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37721 this.list.beginUpdate();
37722 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37723 this.list.alignTo(this.el, this.listAlign);
37724 this.list.endUpdate();
37728 onEmptyResults : function(){
37733 * Returns true if the dropdown list is expanded, else false.
37735 isExpanded : function(){
37736 return this.list.isVisible();
37740 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37741 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37742 * @param {String} value The data value of the item to select
37743 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37744 * selected item if it is not currently in view (defaults to true)
37745 * @return {Boolean} True if the value matched an item in the list, else false
37747 selectByValue : function(v, scrollIntoView){
37748 if(v !== undefined && v !== null){
37749 var r = this.findRecord(this.valueField || this.displayField, v);
37751 this.select(this.store.indexOf(r), scrollIntoView);
37759 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37760 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37761 * @param {Number} index The zero-based index of the list item to select
37762 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37763 * selected item if it is not currently in view (defaults to true)
37765 select : function(index, scrollIntoView){
37766 this.selectedIndex = index;
37767 this.view.select(index);
37768 if(scrollIntoView !== false){
37769 var el = this.view.getNode(index);
37771 this.innerList.scrollChildIntoView(el, false);
37777 selectNext : function(){
37778 var ct = this.store.getCount();
37780 if(this.selectedIndex == -1){
37782 }else if(this.selectedIndex < ct-1){
37783 this.select(this.selectedIndex+1);
37789 selectPrev : function(){
37790 var ct = this.store.getCount();
37792 if(this.selectedIndex == -1){
37794 }else if(this.selectedIndex != 0){
37795 this.select(this.selectedIndex-1);
37801 onKeyUp : function(e){
37802 if(this.editable !== false && !e.isSpecialKey()){
37803 this.lastKey = e.getKey();
37804 this.dqTask.delay(this.queryDelay);
37809 validateBlur : function(){
37810 return !this.list || !this.list.isVisible();
37814 initQuery : function(){
37815 this.doQuery(this.getRawValue());
37819 doForce : function(){
37820 if(this.el.dom.value.length > 0){
37821 this.el.dom.value =
37822 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37823 this.applyEmptyText();
37828 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37829 * query allowing the query action to be canceled if needed.
37830 * @param {String} query The SQL query to execute
37831 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37832 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37833 * saved in the current store (defaults to false)
37835 doQuery : function(q, forceAll){
37836 if(q === undefined || q === null){
37841 forceAll: forceAll,
37845 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37849 forceAll = qe.forceAll;
37850 if(forceAll === true || (q.length >= this.minChars)){
37851 if(this.lastQuery != q || this.alwaysQuery){
37852 this.lastQuery = q;
37853 if(this.mode == 'local'){
37854 this.selectedIndex = -1;
37856 this.store.clearFilter();
37858 this.store.filter(this.displayField, q);
37862 this.store.baseParams[this.queryParam] = q;
37864 params: this.getParams(q)
37869 this.selectedIndex = -1;
37876 getParams : function(q){
37878 //p[this.queryParam] = q;
37881 p.limit = this.pageSize;
37887 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37889 collapse : function(){
37890 if(!this.isExpanded()){
37894 Roo.get(document).un('mousedown', this.collapseIf, this);
37895 Roo.get(document).un('mousewheel', this.collapseIf, this);
37896 if (!this.editable) {
37897 Roo.get(document).un('keydown', this.listKeyPress, this);
37899 this.fireEvent('collapse', this);
37903 collapseIf : function(e){
37904 if(!e.within(this.wrap) && !e.within(this.list)){
37910 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37912 expand : function(){
37913 if(this.isExpanded() || !this.hasFocus){
37916 this.list.alignTo(this.el, this.listAlign);
37918 Roo.get(document).on('mousedown', this.collapseIf, this);
37919 Roo.get(document).on('mousewheel', this.collapseIf, this);
37920 if (!this.editable) {
37921 Roo.get(document).on('keydown', this.listKeyPress, this);
37924 this.fireEvent('expand', this);
37928 // Implements the default empty TriggerField.onTriggerClick function
37929 onTriggerClick : function(){
37933 if(this.isExpanded()){
37935 if (!this.blockFocus) {
37940 this.hasFocus = true;
37941 if(this.triggerAction == 'all') {
37942 this.doQuery(this.allQuery, true);
37944 this.doQuery(this.getRawValue());
37946 if (!this.blockFocus) {
37951 listKeyPress : function(e)
37953 //Roo.log('listkeypress');
37954 // scroll to first matching element based on key pres..
37955 if (e.isSpecialKey()) {
37958 var k = String.fromCharCode(e.getKey()).toUpperCase();
37961 var csel = this.view.getSelectedNodes();
37962 var cselitem = false;
37964 var ix = this.view.indexOf(csel[0]);
37965 cselitem = this.store.getAt(ix);
37966 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
37972 this.store.each(function(v) {
37974 // start at existing selection.
37975 if (cselitem.id == v.id) {
37981 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
37982 match = this.store.indexOf(v);
37987 if (match === false) {
37988 return true; // no more action?
37991 this.view.select(match);
37992 var sn = Roo.get(this.view.getSelectedNodes()[0])
37993 sn.scrollIntoView(sn.dom.parentNode, false);
37997 * @cfg {Boolean} grow
38001 * @cfg {Number} growMin
38005 * @cfg {Number} growMax
38014 * Ext JS Library 1.1.1
38015 * Copyright(c) 2006-2007, Ext JS, LLC.
38017 * Originally Released Under LGPL - original licence link has changed is not relivant.
38020 * <script type="text/javascript">
38023 * @class Roo.form.Checkbox
38024 * @extends Roo.form.Field
38025 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38027 * Creates a new Checkbox
38028 * @param {Object} config Configuration options
38030 Roo.form.Checkbox = function(config){
38031 Roo.form.Checkbox.superclass.constructor.call(this, config);
38035 * Fires when the checkbox is checked or unchecked.
38036 * @param {Roo.form.Checkbox} this This checkbox
38037 * @param {Boolean} checked The new checked value
38043 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38045 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38047 focusClass : undefined,
38049 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38051 fieldClass: "x-form-field",
38053 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38057 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38058 * {tag: "input", type: "checkbox", autocomplete: "off"})
38060 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38062 * @cfg {String} boxLabel The text that appears beside the checkbox
38066 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38070 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38072 valueOff: '0', // value when not checked..
38074 actionMode : 'viewEl',
38077 itemCls : 'x-menu-check-item x-form-item',
38078 groupClass : 'x-menu-group-item',
38079 inputType : 'hidden',
38082 inSetChecked: false, // check that we are not calling self...
38084 inputElement: false, // real input element?
38085 basedOn: false, // ????
38087 isFormField: true, // not sure where this is needed!!!!
38089 onResize : function(){
38090 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38091 if(!this.boxLabel){
38092 this.el.alignTo(this.wrap, 'c-c');
38096 initEvents : function(){
38097 Roo.form.Checkbox.superclass.initEvents.call(this);
38098 this.el.on("click", this.onClick, this);
38099 this.el.on("change", this.onClick, this);
38103 getResizeEl : function(){
38107 getPositionEl : function(){
38112 onRender : function(ct, position){
38113 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38115 if(this.inputValue !== undefined){
38116 this.el.dom.value = this.inputValue;
38119 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38120 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38121 var viewEl = this.wrap.createChild({
38122 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38123 this.viewEl = viewEl;
38124 this.wrap.on('click', this.onClick, this);
38126 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38127 this.el.on('propertychange', this.setFromHidden, this); //ie
38132 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38133 // viewEl.on('click', this.onClick, this);
38135 //if(this.checked){
38136 this.setChecked(this.checked);
38138 //this.checked = this.el.dom;
38144 initValue : Roo.emptyFn,
38147 * Returns the checked state of the checkbox.
38148 * @return {Boolean} True if checked, else false
38150 getValue : function(){
38152 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38154 return this.valueOff;
38159 onClick : function(){
38160 this.setChecked(!this.checked);
38162 //if(this.el.dom.checked != this.checked){
38163 // this.setValue(this.el.dom.checked);
38168 * Sets the checked state of the checkbox.
38169 * On is always based on a string comparison between inputValue and the param.
38170 * @param {Boolean/String} value - the value to set
38171 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38173 setValue : function(v,suppressEvent){
38176 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38177 //if(this.el && this.el.dom){
38178 // this.el.dom.checked = this.checked;
38179 // this.el.dom.defaultChecked = this.checked;
38181 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38182 //this.fireEvent("check", this, this.checked);
38185 setChecked : function(state,suppressEvent)
38187 if (this.inSetChecked) {
38188 this.checked = state;
38194 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38196 this.checked = state;
38197 if(suppressEvent !== true){
38198 this.fireEvent('check', this, state);
38200 this.inSetChecked = true;
38201 this.el.dom.value = state ? this.inputValue : this.valueOff;
38202 this.inSetChecked = false;
38205 // handle setting of hidden value by some other method!!?!?
38206 setFromHidden: function()
38211 //console.log("SET FROM HIDDEN");
38212 //alert('setFrom hidden');
38213 this.setValue(this.el.dom.value);
38216 onDestroy : function()
38219 Roo.get(this.viewEl).remove();
38222 Roo.form.Checkbox.superclass.onDestroy.call(this);
38227 * Ext JS Library 1.1.1
38228 * Copyright(c) 2006-2007, Ext JS, LLC.
38230 * Originally Released Under LGPL - original licence link has changed is not relivant.
38233 * <script type="text/javascript">
38237 * @class Roo.form.Radio
38238 * @extends Roo.form.Checkbox
38239 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38240 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38242 * Creates a new Radio
38243 * @param {Object} config Configuration options
38245 Roo.form.Radio = function(){
38246 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38248 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38249 inputType: 'radio',
38252 * If this radio is part of a group, it will return the selected value
38255 getGroupValue : function(){
38256 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38258 });//<script type="text/javascript">
38261 * Ext JS Library 1.1.1
38262 * Copyright(c) 2006-2007, Ext JS, LLC.
38263 * licensing@extjs.com
38265 * http://www.extjs.com/license
38271 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38272 * - IE ? - no idea how much works there.
38280 * @class Ext.form.HtmlEditor
38281 * @extends Ext.form.Field
38282 * Provides a lightweight HTML Editor component.
38283 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38285 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38286 * supported by this editor.</b><br/><br/>
38287 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38288 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38290 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38292 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38296 * @cfg {String} createLinkText The default text for the create link prompt
38298 createLinkText : 'Please enter the URL for the link:',
38300 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38302 defaultLinkValue : 'http:/'+'/',
38308 // private properties
38309 validationEvent : false,
38311 initialized : false,
38313 sourceEditMode : false,
38314 onFocus : Roo.emptyFn,
38316 hideMode:'offsets',
38317 defaultAutoCreate : {
38319 style:"width:500px;height:300px;",
38320 autocomplete: "off"
38324 initComponent : function(){
38327 * @event initialize
38328 * Fires when the editor is fully initialized (including the iframe)
38329 * @param {HtmlEditor} this
38334 * Fires when the editor is first receives the focus. Any insertion must wait
38335 * until after this event.
38336 * @param {HtmlEditor} this
38340 * @event beforesync
38341 * Fires before the textarea is updated with content from the editor iframe. Return false
38342 * to cancel the sync.
38343 * @param {HtmlEditor} this
38344 * @param {String} html
38348 * @event beforepush
38349 * Fires before the iframe editor is updated with content from the textarea. Return false
38350 * to cancel the push.
38351 * @param {HtmlEditor} this
38352 * @param {String} html
38357 * Fires when the textarea is updated with content from the editor iframe.
38358 * @param {HtmlEditor} this
38359 * @param {String} html
38364 * Fires when the iframe editor is updated with content from the textarea.
38365 * @param {HtmlEditor} this
38366 * @param {String} html
38370 * @event editmodechange
38371 * Fires when the editor switches edit modes
38372 * @param {HtmlEditor} this
38373 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38375 editmodechange: true,
38377 * @event editorevent
38378 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38379 * @param {HtmlEditor} this
38386 * Protected method that will not generally be called directly. It
38387 * is called when the editor creates its toolbar. Override this method if you need to
38388 * add custom toolbar buttons.
38389 * @param {HtmlEditor} editor
38391 createToolbar : function(editor){
38392 if (!editor.toolbars || !editor.toolbars.length) {
38393 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38396 for (var i =0 ; i < editor.toolbars.length;i++) {
38397 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38398 editor.toolbars[i].init(editor);
38405 * Protected method that will not generally be called directly. It
38406 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38407 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38409 getDocMarkup : function(){
38410 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38414 onRender : function(ct, position){
38415 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38416 this.el.dom.style.border = '0 none';
38417 this.el.dom.setAttribute('tabIndex', -1);
38418 this.el.addClass('x-hidden');
38419 if(Roo.isIE){ // fix IE 1px bogus margin
38420 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38422 this.wrap = this.el.wrap({
38423 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38426 this.frameId = Roo.id();
38427 this.createToolbar(this);
38434 var iframe = this.wrap.createChild({
38437 name: this.frameId,
38438 frameBorder : 'no',
38439 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38442 // console.log(iframe);
38443 //this.wrap.dom.appendChild(iframe);
38445 this.iframe = iframe.dom;
38447 this.assignDocWin();
38449 this.doc.designMode = 'on';
38452 this.doc.write(this.getDocMarkup());
38456 var task = { // must defer to wait for browser to be ready
38458 //console.log("run task?" + this.doc.readyState);
38459 this.assignDocWin();
38460 if(this.doc.body || this.doc.readyState == 'complete'){
38462 this.doc.designMode="on";
38466 Roo.TaskMgr.stop(task);
38467 this.initEditor.defer(10, this);
38474 Roo.TaskMgr.start(task);
38477 this.setSize(this.el.getSize());
38482 onResize : function(w, h){
38483 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38484 if(this.el && this.iframe){
38485 if(typeof w == 'number'){
38486 var aw = w - this.wrap.getFrameWidth('lr');
38487 this.el.setWidth(this.adjustWidth('textarea', aw));
38488 this.iframe.style.width = aw + 'px';
38490 if(typeof h == 'number'){
38492 for (var i =0; i < this.toolbars.length;i++) {
38493 // fixme - ask toolbars for heights?
38494 tbh += this.toolbars[i].tb.el.getHeight();
38500 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38501 this.el.setHeight(this.adjustWidth('textarea', ah));
38502 this.iframe.style.height = ah + 'px';
38504 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38511 * Toggles the editor between standard and source edit mode.
38512 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38514 toggleSourceEdit : function(sourceEditMode){
38516 this.sourceEditMode = sourceEditMode === true;
38518 if(this.sourceEditMode){
38521 this.iframe.className = 'x-hidden';
38522 this.el.removeClass('x-hidden');
38523 this.el.dom.removeAttribute('tabIndex');
38528 this.iframe.className = '';
38529 this.el.addClass('x-hidden');
38530 this.el.dom.setAttribute('tabIndex', -1);
38533 this.setSize(this.wrap.getSize());
38534 this.fireEvent('editmodechange', this, this.sourceEditMode);
38537 // private used internally
38538 createLink : function(){
38539 var url = prompt(this.createLinkText, this.defaultLinkValue);
38540 if(url && url != 'http:/'+'/'){
38541 this.relayCmd('createlink', url);
38545 // private (for BoxComponent)
38546 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38548 // private (for BoxComponent)
38549 getResizeEl : function(){
38553 // private (for BoxComponent)
38554 getPositionEl : function(){
38559 initEvents : function(){
38560 this.originalValue = this.getValue();
38564 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38567 markInvalid : Roo.emptyFn,
38569 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38572 clearInvalid : Roo.emptyFn,
38574 setValue : function(v){
38575 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38580 * Protected method that will not generally be called directly. If you need/want
38581 * custom HTML cleanup, this is the method you should override.
38582 * @param {String} html The HTML to be cleaned
38583 * return {String} The cleaned HTML
38585 cleanHtml : function(html){
38586 html = String(html);
38587 if(html.length > 5){
38588 if(Roo.isSafari){ // strip safari nonsense
38589 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38592 if(html == ' '){
38599 * Protected method that will not generally be called directly. Syncs the contents
38600 * of the editor iframe with the textarea.
38602 syncValue : function(){
38603 if(this.initialized){
38604 var bd = (this.doc.body || this.doc.documentElement);
38605 var html = bd.innerHTML;
38607 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38608 var m = bs.match(/text-align:(.*?);/i);
38610 html = '<div style="'+m[0]+'">' + html + '</div>';
38613 html = this.cleanHtml(html);
38614 if(this.fireEvent('beforesync', this, html) !== false){
38615 this.el.dom.value = html;
38616 this.fireEvent('sync', this, html);
38622 * Protected method that will not generally be called directly. Pushes the value of the textarea
38623 * into the iframe editor.
38625 pushValue : function(){
38626 if(this.initialized){
38627 var v = this.el.dom.value;
38631 if(this.fireEvent('beforepush', this, v) !== false){
38632 (this.doc.body || this.doc.documentElement).innerHTML = v;
38633 this.fireEvent('push', this, v);
38639 deferFocus : function(){
38640 this.focus.defer(10, this);
38644 focus : function(){
38645 if(this.win && !this.sourceEditMode){
38652 assignDocWin: function()
38654 var iframe = this.iframe;
38657 this.doc = iframe.contentWindow.document;
38658 this.win = iframe.contentWindow;
38660 if (!Roo.get(this.frameId)) {
38663 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38664 this.win = Roo.get(this.frameId).dom.contentWindow;
38669 initEditor : function(){
38670 //console.log("INIT EDITOR");
38671 this.assignDocWin();
38675 this.doc.designMode="on";
38677 this.doc.write(this.getDocMarkup());
38680 var dbody = (this.doc.body || this.doc.documentElement);
38681 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38682 // this copies styles from the containing element into thsi one..
38683 // not sure why we need all of this..
38684 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38685 ss['background-attachment'] = 'fixed'; // w3c
38686 dbody.bgProperties = 'fixed'; // ie
38687 Roo.DomHelper.applyStyles(dbody, ss);
38688 Roo.EventManager.on(this.doc, {
38689 'mousedown': this.onEditorEvent,
38690 'dblclick': this.onEditorEvent,
38691 'click': this.onEditorEvent,
38692 'keyup': this.onEditorEvent,
38697 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38699 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38700 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38702 this.initialized = true;
38704 this.fireEvent('initialize', this);
38709 onDestroy : function(){
38715 for (var i =0; i < this.toolbars.length;i++) {
38716 // fixme - ask toolbars for heights?
38717 this.toolbars[i].onDestroy();
38720 this.wrap.dom.innerHTML = '';
38721 this.wrap.remove();
38726 onFirstFocus : function(){
38728 this.assignDocWin();
38731 this.activated = true;
38732 for (var i =0; i < this.toolbars.length;i++) {
38733 this.toolbars[i].onFirstFocus();
38736 if(Roo.isGecko){ // prevent silly gecko errors
38738 var s = this.win.getSelection();
38739 if(!s.focusNode || s.focusNode.nodeType != 3){
38740 var r = s.getRangeAt(0);
38741 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38746 this.execCmd('useCSS', true);
38747 this.execCmd('styleWithCSS', false);
38750 this.fireEvent('activate', this);
38754 adjustFont: function(btn){
38755 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38756 //if(Roo.isSafari){ // safari
38759 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38760 if(Roo.isSafari){ // safari
38761 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38762 v = (v < 10) ? 10 : v;
38763 v = (v > 48) ? 48 : v;
38764 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38769 v = Math.max(1, v+adjust);
38771 this.execCmd('FontSize', v );
38774 onEditorEvent : function(e){
38775 this.fireEvent('editorevent', this, e);
38776 // this.updateToolbar();
38780 insertTag : function(tg)
38782 // could be a bit smarter... -> wrap the current selected tRoo..
38784 this.execCmd("formatblock", tg);
38788 insertText : function(txt)
38792 range = this.createRange();
38793 range.deleteContents();
38794 //alert(Sender.getAttribute('label'));
38796 range.insertNode(this.doc.createTextNode(txt));
38800 relayBtnCmd : function(btn){
38801 this.relayCmd(btn.cmd);
38805 * Executes a Midas editor command on the editor document and performs necessary focus and
38806 * toolbar updates. <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 relayCmd : function(cmd, value){
38812 this.execCmd(cmd, value);
38813 this.fireEvent('editorevent', this);
38814 //this.updateToolbar();
38819 * Executes a Midas editor command directly on the editor document.
38820 * For visual commands, you should use {@link #relayCmd} instead.
38821 * <b>This should only be called after the editor is initialized.</b>
38822 * @param {String} cmd The Midas command
38823 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38825 execCmd : function(cmd, value){
38826 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38832 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38834 * @param {String} text
38836 insertAtCursor : function(text){
38837 if(!this.activated){
38842 var r = this.doc.selection.createRange();
38849 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38851 this.execCmd('InsertHTML', text);
38856 mozKeyPress : function(e){
38858 var c = e.getCharCode(), cmd;
38861 c = String.fromCharCode(c).toLowerCase();
38872 this.cleanUpPaste.defer(100, this);
38880 e.preventDefault();
38888 fixKeys : function(){ // load time branching for fastest keydown performance
38890 return function(e){
38891 var k = e.getKey(), r;
38894 r = this.doc.selection.createRange();
38897 r.pasteHTML('    ');
38904 r = this.doc.selection.createRange();
38906 var target = r.parentElement();
38907 if(!target || target.tagName.toLowerCase() != 'li'){
38909 r.pasteHTML('<br />');
38915 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38916 this.cleanUpPaste.defer(100, this);
38922 }else if(Roo.isOpera){
38923 return function(e){
38924 var k = e.getKey();
38928 this.execCmd('InsertHTML','    ');
38931 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38932 this.cleanUpPaste.defer(100, this);
38937 }else if(Roo.isSafari){
38938 return function(e){
38939 var k = e.getKey();
38943 this.execCmd('InsertText','\t');
38947 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38948 this.cleanUpPaste.defer(100, this);
38956 getAllAncestors: function()
38958 var p = this.getSelectedNode();
38961 a.push(p); // push blank onto stack..
38962 p = this.getParentElement();
38966 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38970 a.push(this.doc.body);
38974 lastSelNode : false,
38977 getSelection : function()
38979 this.assignDocWin();
38980 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38983 getSelectedNode: function()
38985 // this may only work on Gecko!!!
38987 // should we cache this!!!!
38992 var range = this.createRange(this.getSelection());
38995 var parent = range.parentElement();
38997 var testRange = range.duplicate();
38998 testRange.moveToElementText(parent);
38999 if (testRange.inRange(range)) {
39002 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39005 parent = parent.parentElement;
39011 var ar = range.endContainer.childNodes;
39013 ar = range.commonAncestorContainer.childNodes;
39014 //alert(ar.length);
39017 var other_nodes = [];
39018 var has_other_nodes = false;
39019 for (var i=0;i<ar.length;i++) {
39020 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39023 // fullly contained node.
39025 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39030 // probably selected..
39031 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39032 other_nodes.push(ar[i]);
39035 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39040 has_other_nodes = true;
39042 if (!nodes.length && other_nodes.length) {
39043 nodes= other_nodes;
39045 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39051 createRange: function(sel)
39053 // this has strange effects when using with
39054 // top toolbar - not sure if it's a great idea.
39055 //this.editor.contentWindow.focus();
39056 if (typeof sel != "undefined") {
39058 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39060 return this.doc.createRange();
39063 return this.doc.createRange();
39066 getParentElement: function()
39069 this.assignDocWin();
39070 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39072 var range = this.createRange(sel);
39075 var p = range.commonAncestorContainer;
39076 while (p.nodeType == 3) { // text node
39088 // BC Hacks - cause I cant work out what i was trying to do..
39089 rangeIntersectsNode : function(range, node)
39091 var nodeRange = node.ownerDocument.createRange();
39093 nodeRange.selectNode(node);
39096 nodeRange.selectNodeContents(node);
39099 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39100 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39102 rangeCompareNode : function(range, node) {
39103 var nodeRange = node.ownerDocument.createRange();
39105 nodeRange.selectNode(node);
39107 nodeRange.selectNodeContents(node);
39109 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39110 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39112 if (nodeIsBefore && !nodeIsAfter)
39114 if (!nodeIsBefore && nodeIsAfter)
39116 if (nodeIsBefore && nodeIsAfter)
39122 // private? - in a new class?
39123 cleanUpPaste : function()
39125 // cleans up the whole document..
39126 // console.log('cleanuppaste');
39127 this.cleanUpChildren(this.doc.body)
39131 cleanUpChildren : function (n)
39133 if (!n.childNodes.length) {
39136 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39137 this.cleanUpChild(n.childNodes[i]);
39144 cleanUpChild : function (node)
39146 //console.log(node);
39147 if (node.nodeName == "#text") {
39148 // clean up silly Windows -- stuff?
39151 if (node.nodeName == "#comment") {
39152 node.parentNode.removeChild(node);
39153 // clean up silly Windows -- stuff?
39157 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39159 node.parentNode.removeChild(node);
39163 if (!node.attributes || !node.attributes.length) {
39164 this.cleanUpChildren(node);
39168 function cleanAttr(n,v)
39171 if (v.match(/^\./) || v.match(/^\//)) {
39174 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39177 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39178 node.removeAttribute(n);
39182 function cleanStyle(n,v)
39184 if (v.match(/expression/)) { //XSS?? should we even bother..
39185 node.removeAttribute(n);
39190 var parts = v.split(/;/);
39191 Roo.each(parts, function(p) {
39192 p = p.replace(/\s+/g,'');
39196 var l = p.split(':').shift().replace(/\s+/g,'');
39198 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39199 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39200 node.removeAttribute(n);
39209 for (var i = node.attributes.length-1; i > -1 ; i--) {
39210 var a = node.attributes[i];
39212 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39213 node.removeAttribute(a.name);
39216 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39217 cleanAttr(a.name,a.value); // fixme..
39220 if (a.name == 'style') {
39221 cleanStyle(a.name,a.value);
39223 /// clean up MS crap..
39224 if (a.name == 'class') {
39225 if (a.value.match(/^Mso/)) {
39226 node.className = '';
39236 this.cleanUpChildren(node);
39242 // hide stuff that is not compatible
39256 * @event specialkey
39260 * @cfg {String} fieldClass @hide
39263 * @cfg {String} focusClass @hide
39266 * @cfg {String} autoCreate @hide
39269 * @cfg {String} inputType @hide
39272 * @cfg {String} invalidClass @hide
39275 * @cfg {String} invalidText @hide
39278 * @cfg {String} msgFx @hide
39281 * @cfg {String} validateOnBlur @hide
39285 Roo.form.HtmlEditor.white = [
39286 'area', 'br', 'img', 'input', 'hr', 'wbr',
39288 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39289 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39290 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39291 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39292 'table', 'ul', 'xmp',
39294 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39297 'dir', 'menu', 'ol', 'ul', 'dl',
39303 Roo.form.HtmlEditor.black = [
39304 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39306 'base', 'basefont', 'bgsound', 'blink', 'body',
39307 'frame', 'frameset', 'head', 'html', 'ilayer',
39308 'iframe', 'layer', 'link', 'meta', 'object',
39309 'script', 'style' ,'title', 'xml' // clean later..
39311 Roo.form.HtmlEditor.clean = [
39312 'script', 'style', 'title', 'xml'
39317 Roo.form.HtmlEditor.ablack = [
39321 Roo.form.HtmlEditor.aclean = [
39322 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39326 Roo.form.HtmlEditor.pwhite= [
39327 'http', 'https', 'mailto'
39330 Roo.form.HtmlEditor.cwhite= [
39335 // <script type="text/javascript">
39338 * Ext JS Library 1.1.1
39339 * Copyright(c) 2006-2007, Ext JS, LLC.
39345 * @class Roo.form.HtmlEditorToolbar1
39350 new Roo.form.HtmlEditor({
39353 new Roo.form.HtmlEditorToolbar1({
39354 disable : { fonts: 1 , format: 1, ..., ... , ...],
39360 * @cfg {Object} disable List of elements to disable..
39361 * @cfg {Array} btns List of additional buttons.
39365 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39368 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39371 Roo.apply(this, config);
39372 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39373 // dont call parent... till later.
39376 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39384 * @cfg {Object} disable List of toolbar elements to disable
39389 * @cfg {Array} fontFamilies An array of available font families
39407 // "á" , ?? a acute?
39412 "°" // , // degrees
39414 // "é" , // e ecute
39415 // "ú" , // u ecute?
39418 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39419 "input:submit", "input:button", "select", "textarea", "label" ],
39422 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39424 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39427 * @cfg {String} defaultFont default font to use.
39429 defaultFont: 'tahoma',
39431 fontSelect : false,
39434 formatCombo : false,
39436 init : function(editor)
39438 this.editor = editor;
39441 var fid = editor.frameId;
39443 function btn(id, toggle, handler){
39444 var xid = fid + '-'+ id ;
39448 cls : 'x-btn-icon x-edit-'+id,
39449 enableToggle:toggle !== false,
39450 scope: editor, // was editor...
39451 handler:handler||editor.relayBtnCmd,
39452 clickEvent:'mousedown',
39453 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39460 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39462 // stop form submits
39463 tb.el.on('click', function(e){
39464 e.preventDefault(); // what does this do?
39467 if(!this.disable.font && !Roo.isSafari){
39468 /* why no safari for fonts
39469 editor.fontSelect = tb.el.createChild({
39472 cls:'x-font-select',
39473 html: editor.createFontOptions()
39475 editor.fontSelect.on('change', function(){
39476 var font = editor.fontSelect.dom.value;
39477 editor.relayCmd('fontname', font);
39478 editor.deferFocus();
39481 editor.fontSelect.dom,
39486 if(!this.disable.formats){
39487 this.formatCombo = new Roo.form.ComboBox({
39488 store: new Roo.data.SimpleStore({
39491 data : this.formats // from states.js
39494 //autoCreate : {tag: "div", size: "20"},
39495 displayField:'tag',
39499 triggerAction: 'all',
39500 emptyText:'Add tag',
39501 selectOnFocus:true,
39504 'select': function(c, r, i) {
39505 editor.insertTag(r.get('tag'));
39511 tb.addField(this.formatCombo);
39515 if(!this.disable.format){
39522 if(!this.disable.fontSize){
39527 btn('increasefontsize', false, editor.adjustFont),
39528 btn('decreasefontsize', false, editor.adjustFont)
39533 if(this.disable.colors){
39536 id:editor.frameId +'-forecolor',
39537 cls:'x-btn-icon x-edit-forecolor',
39538 clickEvent:'mousedown',
39539 tooltip: this.buttonTips['forecolor'] || undefined,
39541 menu : new Roo.menu.ColorMenu({
39542 allowReselect: true,
39543 focus: Roo.emptyFn,
39546 selectHandler: function(cp, color){
39547 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39548 editor.deferFocus();
39551 clickEvent:'mousedown'
39554 id:editor.frameId +'backcolor',
39555 cls:'x-btn-icon x-edit-backcolor',
39556 clickEvent:'mousedown',
39557 tooltip: this.buttonTips['backcolor'] || undefined,
39559 menu : new Roo.menu.ColorMenu({
39560 focus: Roo.emptyFn,
39563 allowReselect: true,
39564 selectHandler: function(cp, color){
39566 editor.execCmd('useCSS', false);
39567 editor.execCmd('hilitecolor', color);
39568 editor.execCmd('useCSS', true);
39569 editor.deferFocus();
39571 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39572 Roo.isSafari || Roo.isIE ? '#'+color : color);
39573 editor.deferFocus();
39577 clickEvent:'mousedown'
39582 // now add all the items...
39585 if(!this.disable.alignments){
39588 btn('justifyleft'),
39589 btn('justifycenter'),
39590 btn('justifyright')
39594 //if(!Roo.isSafari){
39595 if(!this.disable.links){
39598 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39602 if(!this.disable.lists){
39605 btn('insertorderedlist'),
39606 btn('insertunorderedlist')
39609 if(!this.disable.sourceEdit){
39612 btn('sourceedit', true, function(btn){
39613 this.toggleSourceEdit(btn.pressed);
39620 // special menu.. - needs to be tidied up..
39621 if (!this.disable.special) {
39624 cls: 'x-edit-none',
39629 for (var i =0; i < this.specialChars.length; i++) {
39630 smenu.menu.items.push({
39632 html: this.specialChars[i],
39633 handler: function(a,b) {
39634 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39647 for(var i =0; i< this.btns.length;i++) {
39648 var b = this.btns[i];
39649 b.cls = 'x-edit-none';
39658 // disable everything...
39660 this.tb.items.each(function(item){
39661 if(item.id != editor.frameId+ '-sourceedit'){
39665 this.rendered = true;
39667 // the all the btns;
39668 editor.on('editorevent', this.updateToolbar, this);
39669 // other toolbars need to implement this..
39670 //editor.on('editmodechange', this.updateToolbar, this);
39676 * Protected method that will not generally be called directly. It triggers
39677 * a toolbar update by reading the markup state of the current selection in the editor.
39679 updateToolbar: function(){
39681 if(!this.editor.activated){
39682 this.editor.onFirstFocus();
39686 var btns = this.tb.items.map,
39687 doc = this.editor.doc,
39688 frameId = this.editor.frameId;
39690 if(!this.disable.font && !Roo.isSafari){
39692 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39693 if(name != this.fontSelect.dom.value){
39694 this.fontSelect.dom.value = name;
39698 if(!this.disable.format){
39699 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39700 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39701 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39703 if(!this.disable.alignments){
39704 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39705 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39706 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39708 if(!Roo.isSafari && !this.disable.lists){
39709 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39710 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39713 var ans = this.editor.getAllAncestors();
39714 if (this.formatCombo) {
39717 var store = this.formatCombo.store;
39718 this.formatCombo.setValue("");
39719 for (var i =0; i < ans.length;i++) {
39720 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39722 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39730 // hides menus... - so this cant be on a menu...
39731 Roo.menu.MenuMgr.hideAll();
39733 //this.editorsyncValue();
39737 createFontOptions : function(){
39738 var buf = [], fs = this.fontFamilies, ff, lc;
39739 for(var i = 0, len = fs.length; i< len; i++){
39741 lc = ff.toLowerCase();
39743 '<option value="',lc,'" style="font-family:',ff,';"',
39744 (this.defaultFont == lc ? ' selected="true">' : '>'),
39749 return buf.join('');
39752 toggleSourceEdit : function(sourceEditMode){
39753 if(sourceEditMode === undefined){
39754 sourceEditMode = !this.sourceEditMode;
39756 this.sourceEditMode = sourceEditMode === true;
39757 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39758 // just toggle the button?
39759 if(btn.pressed !== this.editor.sourceEditMode){
39760 btn.toggle(this.editor.sourceEditMode);
39764 if(this.sourceEditMode){
39765 this.tb.items.each(function(item){
39766 if(item.cmd != 'sourceedit'){
39772 if(this.initialized){
39773 this.tb.items.each(function(item){
39779 // tell the editor that it's been pressed..
39780 this.editor.toggleSourceEdit(sourceEditMode);
39784 * Object collection of toolbar tooltips for the buttons in the editor. The key
39785 * is the command id associated with that button and the value is a valid QuickTips object.
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'
39805 title: 'Bold (Ctrl+B)',
39806 text: 'Make the selected text bold.',
39807 cls: 'x-html-editor-tip'
39810 title: 'Italic (Ctrl+I)',
39811 text: 'Make the selected text italic.',
39812 cls: 'x-html-editor-tip'
39815 title: 'Underline (Ctrl+U)',
39816 text: 'Underline the selected text.',
39817 cls: 'x-html-editor-tip'
39819 increasefontsize : {
39820 title: 'Grow Text',
39821 text: 'Increase the font size.',
39822 cls: 'x-html-editor-tip'
39824 decreasefontsize : {
39825 title: 'Shrink Text',
39826 text: 'Decrease the font size.',
39827 cls: 'x-html-editor-tip'
39830 title: 'Text Highlight Color',
39831 text: 'Change the background color of the selected text.',
39832 cls: 'x-html-editor-tip'
39835 title: 'Font Color',
39836 text: 'Change the color of the selected text.',
39837 cls: 'x-html-editor-tip'
39840 title: 'Align Text Left',
39841 text: 'Align text to the left.',
39842 cls: 'x-html-editor-tip'
39845 title: 'Center Text',
39846 text: 'Center text in the editor.',
39847 cls: 'x-html-editor-tip'
39850 title: 'Align Text Right',
39851 text: 'Align text to the right.',
39852 cls: 'x-html-editor-tip'
39854 insertunorderedlist : {
39855 title: 'Bullet List',
39856 text: 'Start a bulleted list.',
39857 cls: 'x-html-editor-tip'
39859 insertorderedlist : {
39860 title: 'Numbered List',
39861 text: 'Start a numbered list.',
39862 cls: 'x-html-editor-tip'
39865 title: 'Hyperlink',
39866 text: 'Make the selected text a hyperlink.',
39867 cls: 'x-html-editor-tip'
39870 title: 'Source Edit',
39871 text: 'Switch to source editing mode.',
39872 cls: 'x-html-editor-tip'
39876 onDestroy : function(){
39879 this.tb.items.each(function(item){
39881 item.menu.removeAll();
39883 item.menu.el.destroy();
39891 onFirstFocus: function() {
39892 this.tb.items.each(function(item){
39901 // <script type="text/javascript">
39904 * Ext JS Library 1.1.1
39905 * Copyright(c) 2006-2007, Ext JS, LLC.
39912 * @class Roo.form.HtmlEditor.ToolbarContext
39917 new Roo.form.HtmlEditor({
39920 new Roo.form.HtmlEditor.ToolbarStandard(),
39921 new Roo.form.HtmlEditor.ToolbarContext()
39926 * @config : {Object} disable List of elements to disable.. (not done yet.)
39931 Roo.form.HtmlEditor.ToolbarContext = function(config)
39934 Roo.apply(this, config);
39935 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39936 // dont call parent... till later.
39938 Roo.form.HtmlEditor.ToolbarContext.types = {
39950 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40012 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40017 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40081 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40089 * @cfg {Object} disable List of toolbar elements to disable
40098 init : function(editor)
40100 this.editor = editor;
40103 var fid = editor.frameId;
40105 function btn(id, toggle, handler){
40106 var xid = fid + '-'+ id ;
40110 cls : 'x-btn-icon x-edit-'+id,
40111 enableToggle:toggle !== false,
40112 scope: editor, // was editor...
40113 handler:handler||editor.relayBtnCmd,
40114 clickEvent:'mousedown',
40115 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40119 // create a new element.
40120 var wdiv = editor.wrap.createChild({
40122 }, editor.wrap.dom.firstChild.nextSibling, true);
40124 // can we do this more than once??
40126 // stop form submits
40129 // disable everything...
40130 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40131 this.toolbars = {};
40133 for (var i in ty) {
40135 this.toolbars[i] = this.buildToolbar(ty[i],i);
40137 this.tb = this.toolbars.BODY;
40141 this.rendered = true;
40143 // the all the btns;
40144 editor.on('editorevent', this.updateToolbar, this);
40145 // other toolbars need to implement this..
40146 //editor.on('editmodechange', this.updateToolbar, this);
40152 * Protected method that will not generally be called directly. It triggers
40153 * a toolbar update by reading the markup state of the current selection in the editor.
40155 updateToolbar: function(){
40157 if(!this.editor.activated){
40158 this.editor.onFirstFocus();
40163 var ans = this.editor.getAllAncestors();
40166 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40167 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40168 sel = sel ? sel : this.editor.doc.body;
40169 sel = sel.tagName.length ? sel : this.editor.doc.body;
40170 var tn = sel.tagName.toUpperCase();
40171 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40172 tn = sel.tagName.toUpperCase();
40173 if (this.tb.name == tn) {
40174 return; // no change
40177 ///console.log("show: " + tn);
40178 this.tb = this.toolbars[tn];
40180 this.tb.fields.each(function(e) {
40181 e.setValue(sel.getAttribute(e.name));
40183 this.tb.selectedNode = sel;
40186 Roo.menu.MenuMgr.hideAll();
40188 //this.editorsyncValue();
40193 onDestroy : function(){
40196 this.tb.items.each(function(item){
40198 item.menu.removeAll();
40200 item.menu.el.destroy();
40208 onFirstFocus: function() {
40209 // need to do this for all the toolbars..
40210 this.tb.items.each(function(item){
40214 buildToolbar: function(tlist, nm)
40216 var editor = this.editor;
40217 // create a new element.
40218 var wdiv = editor.wrap.createChild({
40220 }, editor.wrap.dom.firstChild.nextSibling, true);
40223 var tb = new Roo.Toolbar(wdiv);
40224 tb.add(nm+ ": ");
40225 for (var i in tlist) {
40226 var item = tlist[i];
40227 tb.add(item.title + ": ");
40232 tb.addField( new Roo.form.ComboBox({
40233 store: new Roo.data.SimpleStore({
40236 data : item.opts // from states.js
40239 displayField:'val',
40243 triggerAction: 'all',
40244 emptyText:'Select',
40245 selectOnFocus:true,
40246 width: item.width ? item.width : 130,
40248 'select': function(c, r, i) {
40249 tb.selectedNode.setAttribute(c.name, r.get('val'));
40260 tb.addField( new Roo.form.TextField({
40263 //allowBlank:false,
40268 tb.addField( new Roo.form.TextField({
40274 'change' : function(f, nv, ov) {
40275 tb.selectedNode.setAttribute(f.name, nv);
40281 tb.el.on('click', function(e){
40282 e.preventDefault(); // what does this do?
40284 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40287 // dont need to disable them... as they will get hidden
40304 * Ext JS Library 1.1.1
40305 * Copyright(c) 2006-2007, Ext JS, LLC.
40307 * Originally Released Under LGPL - original licence link has changed is not relivant.
40310 * <script type="text/javascript">
40314 * @class Roo.form.BasicForm
40315 * @extends Roo.util.Observable
40316 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40318 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40319 * @param {Object} config Configuration options
40321 Roo.form.BasicForm = function(el, config){
40322 this.allItems = [];
40323 this.childForms = [];
40324 Roo.apply(this, config);
40326 * The Roo.form.Field items in this form.
40327 * @type MixedCollection
40331 this.items = new Roo.util.MixedCollection(false, function(o){
40332 return o.id || (o.id = Roo.id());
40336 * @event beforeaction
40337 * Fires before any action is performed. Return false to cancel the action.
40338 * @param {Form} this
40339 * @param {Action} action The action to be performed
40341 beforeaction: true,
40343 * @event actionfailed
40344 * Fires when an action fails.
40345 * @param {Form} this
40346 * @param {Action} action The action that failed
40348 actionfailed : true,
40350 * @event actioncomplete
40351 * Fires when an action is completed.
40352 * @param {Form} this
40353 * @param {Action} action The action that completed
40355 actioncomplete : true
40360 Roo.form.BasicForm.superclass.constructor.call(this);
40363 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40365 * @cfg {String} method
40366 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40369 * @cfg {DataReader} reader
40370 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40371 * This is optional as there is built-in support for processing JSON.
40374 * @cfg {DataReader} errorReader
40375 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40376 * This is completely optional as there is built-in support for processing JSON.
40379 * @cfg {String} url
40380 * The URL to use for form actions if one isn't supplied in the action options.
40383 * @cfg {Boolean} fileUpload
40384 * Set to true if this form is a file upload.
40388 * @cfg {Object} baseParams
40389 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40394 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40399 activeAction : null,
40402 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40403 * or setValues() data instead of when the form was first created.
40405 trackResetOnLoad : false,
40409 * childForms - used for multi-tab forms
40412 childForms : false,
40415 * allItems - full list of fields.
40421 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40422 * element by passing it or its id or mask the form itself by passing in true.
40425 waitMsgTarget : false,
40428 initEl : function(el){
40429 this.el = Roo.get(el);
40430 this.id = this.el.id || Roo.id();
40431 this.el.on('submit', this.onSubmit, this);
40432 this.el.addClass('x-form');
40436 onSubmit : function(e){
40441 * Returns true if client-side validation on the form is successful.
40444 isValid : function(){
40446 this.items.each(function(f){
40455 * Returns true if any fields in this form have changed since their original load.
40458 isDirty : function(){
40460 this.items.each(function(f){
40470 * Performs a predefined action (submit or load) or custom actions you define on this form.
40471 * @param {String} actionName The name of the action type
40472 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40473 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40474 * accept other config options):
40476 Property Type Description
40477 ---------------- --------------- ----------------------------------------------------------------------------------
40478 url String The url for the action (defaults to the form's url)
40479 method String The form method to use (defaults to the form's method, or POST if not defined)
40480 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40481 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40482 validate the form on the client (defaults to false)
40484 * @return {BasicForm} this
40486 doAction : function(action, options){
40487 if(typeof action == 'string'){
40488 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40490 if(this.fireEvent('beforeaction', this, action) !== false){
40491 this.beforeAction(action);
40492 action.run.defer(100, action);
40498 * Shortcut to do a submit action.
40499 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40500 * @return {BasicForm} this
40502 submit : function(options){
40503 this.doAction('submit', options);
40508 * Shortcut to do a load action.
40509 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40510 * @return {BasicForm} this
40512 load : function(options){
40513 this.doAction('load', options);
40518 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40519 * @param {Record} record The record to edit
40520 * @return {BasicForm} this
40522 updateRecord : function(record){
40523 record.beginEdit();
40524 var fs = record.fields;
40525 fs.each(function(f){
40526 var field = this.findField(f.name);
40528 record.set(f.name, field.getValue());
40536 * Loads an Roo.data.Record into this form.
40537 * @param {Record} record The record to load
40538 * @return {BasicForm} this
40540 loadRecord : function(record){
40541 this.setValues(record.data);
40546 beforeAction : function(action){
40547 var o = action.options;
40550 if(this.waitMsgTarget === true){
40551 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
40552 }else if(this.waitMsgTarget){
40553 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40554 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
40556 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
40562 afterAction : function(action, success){
40563 this.activeAction = null;
40564 var o = action.options;
40566 if(this.waitMsgTarget === true){
40568 }else if(this.waitMsgTarget){
40569 this.waitMsgTarget.unmask();
40571 Roo.MessageBox.updateProgress(1);
40572 Roo.MessageBox.hide();
40579 Roo.callback(o.success, o.scope, [this, action]);
40580 this.fireEvent('actioncomplete', this, action);
40583 Roo.callback(o.failure, o.scope, [this, action]);
40584 // show an error message if no failed handler is set..
40585 if (!this.hasListener('actionfailed')) {
40586 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
40589 this.fireEvent('actionfailed', this, action);
40595 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40596 * @param {String} id The value to search for
40599 findField : function(id){
40600 var field = this.items.get(id);
40602 this.items.each(function(f){
40603 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40609 return field || null;
40613 * Add a secondary form to this one,
40614 * Used to provide tabbed forms. One form is primary, with hidden values
40615 * which mirror the elements from the other forms.
40617 * @param {Roo.form.Form} form to add.
40620 addForm : function(form)
40623 if (this.childForms.indexOf(form) > -1) {
40627 this.childForms.push(form);
40629 Roo.each(form.allItems, function (fe) {
40631 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40632 if (this.findField(n)) { // already added..
40635 var add = new Roo.form.Hidden({
40638 add.render(this.el);
40645 * Mark fields in this form invalid in bulk.
40646 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40647 * @return {BasicForm} this
40649 markInvalid : function(errors){
40650 if(errors instanceof Array){
40651 for(var i = 0, len = errors.length; i < len; i++){
40652 var fieldError = errors[i];
40653 var f = this.findField(fieldError.id);
40655 f.markInvalid(fieldError.msg);
40661 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40662 field.markInvalid(errors[id]);
40666 Roo.each(this.childForms || [], function (f) {
40667 f.markInvalid(errors);
40674 * Set values for fields in this form in bulk.
40675 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40676 * @return {BasicForm} this
40678 setValues : function(values){
40679 if(values instanceof Array){ // array of objects
40680 for(var i = 0, len = values.length; i < len; i++){
40682 var f = this.findField(v.id);
40684 f.setValue(v.value);
40685 if(this.trackResetOnLoad){
40686 f.originalValue = f.getValue();
40690 }else{ // object hash
40693 if(typeof values[id] != 'function' && (field = this.findField(id))){
40695 if (field.setFromData &&
40696 field.valueField &&
40697 field.displayField &&
40698 // combos' with local stores can
40699 // be queried via setValue()
40700 // to set their value..
40701 (field.store && !field.store.isLocal)
40705 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40706 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40707 field.setFromData(sd);
40710 field.setValue(values[id]);
40714 if(this.trackResetOnLoad){
40715 field.originalValue = field.getValue();
40721 Roo.each(this.childForms || [], function (f) {
40722 f.setValues(values);
40729 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40730 * they are returned as an array.
40731 * @param {Boolean} asString
40734 getValues : function(asString){
40735 if (this.childForms) {
40736 // copy values from the child forms
40737 Roo.each(this.childForms, function (f) {
40738 this.setValues(f.getValues());
40744 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40745 if(asString === true){
40748 return Roo.urlDecode(fs);
40752 * Returns the fields in this form as an object with key/value pairs.
40753 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40756 getFieldValues : function()
40758 if (this.childForms) {
40759 // copy values from the child forms
40760 Roo.each(this.childForms, function (f) {
40761 this.setValues(f.getValues());
40766 this.items.each(function(f){
40767 if (!f.getName()) {
40770 var v = f.getValue();
40771 if ((typeof(v) == 'object') && f.getRawValue) {
40772 v = f.getRawValue() ; // dates..
40774 ret[f.getName()] = v;
40781 * Clears all invalid messages in this form.
40782 * @return {BasicForm} this
40784 clearInvalid : function(){
40785 this.items.each(function(f){
40789 Roo.each(this.childForms || [], function (f) {
40798 * Resets this form.
40799 * @return {BasicForm} this
40801 reset : function(){
40802 this.items.each(function(f){
40806 Roo.each(this.childForms || [], function (f) {
40815 * Add Roo.form components to this form.
40816 * @param {Field} field1
40817 * @param {Field} field2 (optional)
40818 * @param {Field} etc (optional)
40819 * @return {BasicForm} this
40822 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40828 * Removes a field from the items collection (does NOT remove its markup).
40829 * @param {Field} field
40830 * @return {BasicForm} this
40832 remove : function(field){
40833 this.items.remove(field);
40838 * Looks at the fields in this form, checks them for an id attribute,
40839 * and calls applyTo on the existing dom element with that id.
40840 * @return {BasicForm} this
40842 render : function(){
40843 this.items.each(function(f){
40844 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40852 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40853 * @param {Object} values
40854 * @return {BasicForm} this
40856 applyToFields : function(o){
40857 this.items.each(function(f){
40864 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40865 * @param {Object} values
40866 * @return {BasicForm} this
40868 applyIfToFields : function(o){
40869 this.items.each(function(f){
40877 Roo.BasicForm = Roo.form.BasicForm;/*
40879 * Ext JS Library 1.1.1
40880 * Copyright(c) 2006-2007, Ext JS, LLC.
40882 * Originally Released Under LGPL - original licence link has changed is not relivant.
40885 * <script type="text/javascript">
40889 * @class Roo.form.Form
40890 * @extends Roo.form.BasicForm
40891 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40893 * @param {Object} config Configuration options
40895 Roo.form.Form = function(config){
40897 if (config.items) {
40898 xitems = config.items;
40899 delete config.items;
40903 Roo.form.Form.superclass.constructor.call(this, null, config);
40904 this.url = this.url || this.action;
40906 this.root = new Roo.form.Layout(Roo.applyIf({
40910 this.active = this.root;
40912 * Array of all the buttons that have been added to this form via {@link addButton}
40916 this.allItems = [];
40919 * @event clientvalidation
40920 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40921 * @param {Form} this
40922 * @param {Boolean} valid true if the form has passed client-side validation
40924 clientvalidation: true,
40927 * Fires when the form is rendered
40928 * @param {Roo.form.Form} form
40933 if (this.progressUrl) {
40934 // push a hidden field onto the list of fields..
40938 name : 'UPLOAD_IDENTIFIER'
40943 Roo.each(xitems, this.addxtype, this);
40949 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40951 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40954 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40957 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40959 buttonAlign:'center',
40962 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40967 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40968 * This property cascades to child containers if not set.
40973 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40974 * fires a looping event with that state. This is required to bind buttons to the valid
40975 * state using the config value formBind:true on the button.
40977 monitorValid : false,
40980 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40985 * @cfg {String} progressUrl - Url to return progress data
40988 progressUrl : false,
40991 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40992 * fields are added and the column is closed. If no fields are passed the column remains open
40993 * until end() is called.
40994 * @param {Object} config The config to pass to the column
40995 * @param {Field} field1 (optional)
40996 * @param {Field} field2 (optional)
40997 * @param {Field} etc (optional)
40998 * @return Column The column container object
41000 column : function(c){
41001 var col = new Roo.form.Column(c);
41003 if(arguments.length > 1){ // duplicate code required because of Opera
41004 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41011 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41012 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41013 * until end() is called.
41014 * @param {Object} config The config to pass to the fieldset
41015 * @param {Field} field1 (optional)
41016 * @param {Field} field2 (optional)
41017 * @param {Field} etc (optional)
41018 * @return FieldSet The fieldset container object
41020 fieldset : function(c){
41021 var fs = new Roo.form.FieldSet(c);
41023 if(arguments.length > 1){ // duplicate code required because of Opera
41024 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41031 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41032 * fields are added and the container is closed. If no fields are passed the container remains open
41033 * until end() is called.
41034 * @param {Object} config The config to pass to the Layout
41035 * @param {Field} field1 (optional)
41036 * @param {Field} field2 (optional)
41037 * @param {Field} etc (optional)
41038 * @return Layout The container object
41040 container : function(c){
41041 var l = new Roo.form.Layout(c);
41043 if(arguments.length > 1){ // duplicate code required because of Opera
41044 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41051 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41052 * @param {Object} container A Roo.form.Layout or subclass of Layout
41053 * @return {Form} this
41055 start : function(c){
41056 // cascade label info
41057 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41058 this.active.stack.push(c);
41059 c.ownerCt = this.active;
41065 * Closes the current open container
41066 * @return {Form} this
41069 if(this.active == this.root){
41072 this.active = this.active.ownerCt;
41077 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41078 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41079 * as the label of the field.
41080 * @param {Field} field1
41081 * @param {Field} field2 (optional)
41082 * @param {Field} etc. (optional)
41083 * @return {Form} this
41086 this.active.stack.push.apply(this.active.stack, arguments);
41087 this.allItems.push.apply(this.allItems,arguments);
41089 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41090 if(a[i].isFormField){
41095 Roo.form.Form.superclass.add.apply(this, r);
41105 * Find any element that has been added to a form, using it's ID or name
41106 * This can include framesets, columns etc. along with regular fields..
41107 * @param {String} id - id or name to find.
41109 * @return {Element} e - or false if nothing found.
41111 findbyId : function(id)
41117 Ext.each(this.allItems, function(f){
41118 if (f.id == id || f.name == id ){
41129 * Render this form into the passed container. This should only be called once!
41130 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41131 * @return {Form} this
41133 render : function(ct)
41139 var o = this.autoCreate || {
41141 method : this.method || 'POST',
41142 id : this.id || Roo.id()
41144 this.initEl(ct.createChild(o));
41146 this.root.render(this.el);
41150 this.items.each(function(f){
41151 f.render('x-form-el-'+f.id);
41154 if(this.buttons.length > 0){
41155 // tables are required to maintain order and for correct IE layout
41156 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41157 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41158 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41160 var tr = tb.getElementsByTagName('tr')[0];
41161 for(var i = 0, len = this.buttons.length; i < len; i++) {
41162 var b = this.buttons[i];
41163 var td = document.createElement('td');
41164 td.className = 'x-form-btn-td';
41165 b.render(tr.appendChild(td));
41168 if(this.monitorValid){ // initialize after render
41169 this.startMonitoring();
41171 this.fireEvent('rendered', this);
41176 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41177 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41178 * object or a valid Roo.DomHelper element config
41179 * @param {Function} handler The function called when the button is clicked
41180 * @param {Object} scope (optional) The scope of the handler function
41181 * @return {Roo.Button}
41183 addButton : function(config, handler, scope){
41187 minWidth: this.minButtonWidth,
41190 if(typeof config == "string"){
41193 Roo.apply(bc, config);
41195 var btn = new Roo.Button(null, bc);
41196 this.buttons.push(btn);
41201 * Adds a series of form elements (using the xtype property as the factory method.
41202 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41203 * @param {Object} config
41206 addxtype : function()
41208 var ar = Array.prototype.slice.call(arguments, 0);
41210 for(var i = 0; i < ar.length; i++) {
41212 continue; // skip -- if this happends something invalid got sent, we
41213 // should ignore it, as basically that interface element will not show up
41214 // and that should be pretty obvious!!
41217 if (Roo.form[ar[i].xtype]) {
41219 var fe = Roo.factory(ar[i], Roo.form);
41225 fe.store.form = this;
41230 this.allItems.push(fe);
41231 if (fe.items && fe.addxtype) {
41232 fe.addxtype.apply(fe, fe.items);
41242 // console.log('adding ' + ar[i].xtype);
41244 if (ar[i].xtype == 'Button') {
41245 //console.log('adding button');
41246 //console.log(ar[i]);
41247 this.addButton(ar[i]);
41248 this.allItems.push(fe);
41252 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41253 alert('end is not supported on xtype any more, use items');
41255 // //console.log('adding end');
41263 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41264 * option "monitorValid"
41266 startMonitoring : function(){
41269 Roo.TaskMgr.start({
41270 run : this.bindHandler,
41271 interval : this.monitorPoll || 200,
41278 * Stops monitoring of the valid state of this form
41280 stopMonitoring : function(){
41281 this.bound = false;
41285 bindHandler : function(){
41287 return false; // stops binding
41290 this.items.each(function(f){
41291 if(!f.isValid(true)){
41296 for(var i = 0, len = this.buttons.length; i < len; i++){
41297 var btn = this.buttons[i];
41298 if(btn.formBind === true && btn.disabled === valid){
41299 btn.setDisabled(!valid);
41302 this.fireEvent('clientvalidation', this, valid);
41316 Roo.Form = Roo.form.Form;
41319 * Ext JS Library 1.1.1
41320 * Copyright(c) 2006-2007, Ext JS, LLC.
41322 * Originally Released Under LGPL - original licence link has changed is not relivant.
41325 * <script type="text/javascript">
41329 * @class Roo.form.Action
41330 * Internal Class used to handle form actions
41332 * @param {Roo.form.BasicForm} el The form element or its id
41333 * @param {Object} config Configuration options
41337 // define the action interface
41338 Roo.form.Action = function(form, options){
41340 this.options = options || {};
41343 * Client Validation Failed
41346 Roo.form.Action.CLIENT_INVALID = 'client';
41348 * Server Validation Failed
41351 Roo.form.Action.SERVER_INVALID = 'server';
41353 * Connect to Server Failed
41356 Roo.form.Action.CONNECT_FAILURE = 'connect';
41358 * Reading Data from Server Failed
41361 Roo.form.Action.LOAD_FAILURE = 'load';
41363 Roo.form.Action.prototype = {
41365 failureType : undefined,
41366 response : undefined,
41367 result : undefined,
41369 // interface method
41370 run : function(options){
41374 // interface method
41375 success : function(response){
41379 // interface method
41380 handleResponse : function(response){
41384 // default connection failure
41385 failure : function(response){
41387 this.response = response;
41388 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41389 this.form.afterAction(this, false);
41392 processResponse : function(response){
41393 this.response = response;
41394 if(!response.responseText){
41397 this.result = this.handleResponse(response);
41398 return this.result;
41401 // utility functions used internally
41402 getUrl : function(appendParams){
41403 var url = this.options.url || this.form.url || this.form.el.dom.action;
41405 var p = this.getParams();
41407 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41413 getMethod : function(){
41414 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41417 getParams : function(){
41418 var bp = this.form.baseParams;
41419 var p = this.options.params;
41421 if(typeof p == "object"){
41422 p = Roo.urlEncode(Roo.applyIf(p, bp));
41423 }else if(typeof p == 'string' && bp){
41424 p += '&' + Roo.urlEncode(bp);
41427 p = Roo.urlEncode(bp);
41432 createCallback : function(){
41434 success: this.success,
41435 failure: this.failure,
41437 timeout: (this.form.timeout*1000),
41438 upload: this.form.fileUpload ? this.success : undefined
41443 Roo.form.Action.Submit = function(form, options){
41444 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41447 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41450 haveProgress : false,
41451 uploadComplete : false,
41453 // uploadProgress indicator.
41454 uploadProgress : function()
41456 if (!this.form.progressUrl) {
41460 if (!this.haveProgress) {
41461 Roo.MessageBox.progress("Uploading", "Uploading");
41463 if (this.uploadComplete) {
41464 Roo.MessageBox.hide();
41468 this.haveProgress = true;
41470 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41472 var c = new Roo.data.Connection();
41474 url : this.form.progressUrl,
41479 success : function(req){
41480 //console.log(data);
41484 rdata = Roo.decode(req.responseText)
41486 Roo.log("Invalid data from server..");
41490 if (!rdata || !rdata.success) {
41494 var data = rdata.data;
41496 if (this.uploadComplete) {
41497 Roo.MessageBox.hide();
41502 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41503 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41506 this.uploadProgress.defer(2000,this);
41509 failure: function(data) {
41510 Roo.log('progress url failed ');
41521 // run get Values on the form, so it syncs any secondary forms.
41522 this.form.getValues();
41524 var o = this.options;
41525 var method = this.getMethod();
41526 var isPost = method == 'POST';
41527 if(o.clientValidation === false || this.form.isValid()){
41529 if (this.form.progressUrl) {
41530 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41531 (new Date() * 1) + '' + Math.random());
41536 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41537 form:this.form.el.dom,
41538 url:this.getUrl(!isPost),
41540 params:isPost ? this.getParams() : null,
41541 isUpload: this.form.fileUpload
41544 this.uploadProgress();
41546 }else if (o.clientValidation !== false){ // client validation failed
41547 this.failureType = Roo.form.Action.CLIENT_INVALID;
41548 this.form.afterAction(this, false);
41552 success : function(response)
41554 this.uploadComplete= true;
41555 if (this.haveProgress) {
41556 Roo.MessageBox.hide();
41560 var result = this.processResponse(response);
41561 if(result === true || result.success){
41562 this.form.afterAction(this, true);
41566 this.form.markInvalid(result.errors);
41567 this.failureType = Roo.form.Action.SERVER_INVALID;
41569 this.form.afterAction(this, false);
41571 failure : function(response)
41573 this.uploadComplete= true;
41574 if (this.haveProgress) {
41575 Roo.MessageBox.hide();
41579 this.response = response;
41580 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41581 this.form.afterAction(this, false);
41584 handleResponse : function(response){
41585 if(this.form.errorReader){
41586 var rs = this.form.errorReader.read(response);
41589 for(var i = 0, len = rs.records.length; i < len; i++) {
41590 var r = rs.records[i];
41591 errors[i] = r.data;
41594 if(errors.length < 1){
41598 success : rs.success,
41604 ret = Roo.decode(response.responseText);
41608 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41618 Roo.form.Action.Load = function(form, options){
41619 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41620 this.reader = this.form.reader;
41623 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41628 Roo.Ajax.request(Roo.apply(
41629 this.createCallback(), {
41630 method:this.getMethod(),
41631 url:this.getUrl(false),
41632 params:this.getParams()
41636 success : function(response){
41638 var result = this.processResponse(response);
41639 if(result === true || !result.success || !result.data){
41640 this.failureType = Roo.form.Action.LOAD_FAILURE;
41641 this.form.afterAction(this, false);
41644 this.form.clearInvalid();
41645 this.form.setValues(result.data);
41646 this.form.afterAction(this, true);
41649 handleResponse : function(response){
41650 if(this.form.reader){
41651 var rs = this.form.reader.read(response);
41652 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41654 success : rs.success,
41658 return Roo.decode(response.responseText);
41662 Roo.form.Action.ACTION_TYPES = {
41663 'load' : Roo.form.Action.Load,
41664 'submit' : Roo.form.Action.Submit
41667 * Ext JS Library 1.1.1
41668 * Copyright(c) 2006-2007, Ext JS, LLC.
41670 * Originally Released Under LGPL - original licence link has changed is not relivant.
41673 * <script type="text/javascript">
41677 * @class Roo.form.Layout
41678 * @extends Roo.Component
41679 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41681 * @param {Object} config Configuration options
41683 Roo.form.Layout = function(config){
41685 if (config.items) {
41686 xitems = config.items;
41687 delete config.items;
41689 Roo.form.Layout.superclass.constructor.call(this, config);
41691 Roo.each(xitems, this.addxtype, this);
41695 Roo.extend(Roo.form.Layout, Roo.Component, {
41697 * @cfg {String/Object} autoCreate
41698 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41701 * @cfg {String/Object/Function} style
41702 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41703 * a function which returns such a specification.
41706 * @cfg {String} labelAlign
41707 * Valid values are "left," "top" and "right" (defaults to "left")
41710 * @cfg {Number} labelWidth
41711 * Fixed width in pixels of all field labels (defaults to undefined)
41714 * @cfg {Boolean} clear
41715 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41719 * @cfg {String} labelSeparator
41720 * The separator to use after field labels (defaults to ':')
41722 labelSeparator : ':',
41724 * @cfg {Boolean} hideLabels
41725 * True to suppress the display of field labels in this layout (defaults to false)
41727 hideLabels : false,
41730 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41735 onRender : function(ct, position){
41736 if(this.el){ // from markup
41737 this.el = Roo.get(this.el);
41738 }else { // generate
41739 var cfg = this.getAutoCreate();
41740 this.el = ct.createChild(cfg, position);
41743 this.el.applyStyles(this.style);
41745 if(this.labelAlign){
41746 this.el.addClass('x-form-label-'+this.labelAlign);
41748 if(this.hideLabels){
41749 this.labelStyle = "display:none";
41750 this.elementStyle = "padding-left:0;";
41752 if(typeof this.labelWidth == 'number'){
41753 this.labelStyle = "width:"+this.labelWidth+"px;";
41754 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41756 if(this.labelAlign == 'top'){
41757 this.labelStyle = "width:auto;";
41758 this.elementStyle = "padding-left:0;";
41761 var stack = this.stack;
41762 var slen = stack.length;
41764 if(!this.fieldTpl){
41765 var t = new Roo.Template(
41766 '<div class="x-form-item {5}">',
41767 '<label for="{0}" style="{2}">{1}{4}</label>',
41768 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41770 '</div><div class="x-form-clear-left"></div>'
41772 t.disableFormats = true;
41774 Roo.form.Layout.prototype.fieldTpl = t;
41776 for(var i = 0; i < slen; i++) {
41777 if(stack[i].isFormField){
41778 this.renderField(stack[i]);
41780 this.renderComponent(stack[i]);
41785 this.el.createChild({cls:'x-form-clear'});
41790 renderField : function(f){
41791 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41794 f.labelStyle||this.labelStyle||'', //2
41795 this.elementStyle||'', //3
41796 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41797 f.itemCls||this.itemCls||'' //5
41798 ], true).getPrevSibling());
41802 renderComponent : function(c){
41803 c.render(c.isLayout ? this.el : this.el.createChild());
41806 * Adds a object form elements (using the xtype property as the factory method.)
41807 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41808 * @param {Object} config
41810 addxtype : function(o)
41812 // create the lement.
41813 o.form = this.form;
41814 var fe = Roo.factory(o, Roo.form);
41815 this.form.allItems.push(fe);
41816 this.stack.push(fe);
41818 if (fe.isFormField) {
41819 this.form.items.add(fe);
41827 * @class Roo.form.Column
41828 * @extends Roo.form.Layout
41829 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41831 * @param {Object} config Configuration options
41833 Roo.form.Column = function(config){
41834 Roo.form.Column.superclass.constructor.call(this, config);
41837 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41839 * @cfg {Number/String} width
41840 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41843 * @cfg {String/Object} autoCreate
41844 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41848 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41851 onRender : function(ct, position){
41852 Roo.form.Column.superclass.onRender.call(this, ct, position);
41854 this.el.setWidth(this.width);
41861 * @class Roo.form.Row
41862 * @extends Roo.form.Layout
41863 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41865 * @param {Object} config Configuration options
41869 Roo.form.Row = function(config){
41870 Roo.form.Row.superclass.constructor.call(this, config);
41873 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41875 * @cfg {Number/String} width
41876 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41879 * @cfg {Number/String} height
41880 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41882 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41886 onRender : function(ct, position){
41887 //console.log('row render');
41889 var t = new Roo.Template(
41890 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41891 '<label for="{0}" style="{2}">{1}{4}</label>',
41892 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41896 t.disableFormats = true;
41898 Roo.form.Layout.prototype.rowTpl = t;
41900 this.fieldTpl = this.rowTpl;
41902 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41903 var labelWidth = 100;
41905 if ((this.labelAlign != 'top')) {
41906 if (typeof this.labelWidth == 'number') {
41907 labelWidth = this.labelWidth
41909 this.padWidth = 20 + labelWidth;
41913 Roo.form.Column.superclass.onRender.call(this, ct, position);
41915 this.el.setWidth(this.width);
41918 this.el.setHeight(this.height);
41923 renderField : function(f){
41924 f.fieldEl = this.fieldTpl.append(this.el, [
41925 f.id, f.fieldLabel,
41926 f.labelStyle||this.labelStyle||'',
41927 this.elementStyle||'',
41928 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41929 f.itemCls||this.itemCls||'',
41930 f.width ? f.width + this.padWidth : 160 + this.padWidth
41937 * @class Roo.form.FieldSet
41938 * @extends Roo.form.Layout
41939 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41941 * @param {Object} config Configuration options
41943 Roo.form.FieldSet = function(config){
41944 Roo.form.FieldSet.superclass.constructor.call(this, config);
41947 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41949 * @cfg {String} legend
41950 * The text to display as the legend for the FieldSet (defaults to '')
41953 * @cfg {String/Object} autoCreate
41954 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41958 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41961 onRender : function(ct, position){
41962 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
41964 this.setLegend(this.legend);
41969 setLegend : function(text){
41971 this.el.child('legend').update(text);
41976 * Ext JS Library 1.1.1
41977 * Copyright(c) 2006-2007, Ext JS, LLC.
41979 * Originally Released Under LGPL - original licence link has changed is not relivant.
41982 * <script type="text/javascript">
41985 * @class Roo.form.VTypes
41986 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41989 Roo.form.VTypes = function(){
41990 // closure these in so they are only created once.
41991 var alpha = /^[a-zA-Z_]+$/;
41992 var alphanum = /^[a-zA-Z0-9_]+$/;
41993 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41994 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41996 // All these messages and functions are configurable
41999 * The function used to validate email addresses
42000 * @param {String} value The email address
42002 'email' : function(v){
42003 return email.test(v);
42006 * The error text to display when the email validation function returns false
42009 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42011 * The keystroke filter mask to be applied on email input
42014 'emailMask' : /[a-z0-9_\.\-@]/i,
42017 * The function used to validate URLs
42018 * @param {String} value The URL
42020 'url' : function(v){
42021 return url.test(v);
42024 * The error text to display when the url validation function returns false
42027 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42030 * The function used to validate alpha values
42031 * @param {String} value The value
42033 'alpha' : function(v){
42034 return alpha.test(v);
42037 * The error text to display when the alpha validation function returns false
42040 'alphaText' : 'This field should only contain letters and _',
42042 * The keystroke filter mask to be applied on alpha input
42045 'alphaMask' : /[a-z_]/i,
42048 * The function used to validate alphanumeric values
42049 * @param {String} value The value
42051 'alphanum' : function(v){
42052 return alphanum.test(v);
42055 * The error text to display when the alphanumeric validation function returns false
42058 'alphanumText' : 'This field should only contain letters, numbers and _',
42060 * The keystroke filter mask to be applied on alphanumeric input
42063 'alphanumMask' : /[a-z0-9_]/i
42065 }();//<script type="text/javascript">
42068 * @class Roo.form.FCKeditor
42069 * @extends Roo.form.TextArea
42070 * Wrapper around the FCKEditor http://www.fckeditor.net
42072 * Creates a new FCKeditor
42073 * @param {Object} config Configuration options
42075 Roo.form.FCKeditor = function(config){
42076 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42079 * @event editorinit
42080 * Fired when the editor is initialized - you can add extra handlers here..
42081 * @param {FCKeditor} this
42082 * @param {Object} the FCK object.
42089 Roo.form.FCKeditor.editors = { };
42090 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42092 //defaultAutoCreate : {
42093 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42097 * @cfg {Object} fck options - see fck manual for details.
42102 * @cfg {Object} fck toolbar set (Basic or Default)
42104 toolbarSet : 'Basic',
42106 * @cfg {Object} fck BasePath
42108 basePath : '/fckeditor/',
42116 onRender : function(ct, position)
42119 this.defaultAutoCreate = {
42121 style:"width:300px;height:60px;",
42122 autocomplete: "off"
42125 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42128 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42129 if(this.preventScrollbars){
42130 this.el.setStyle("overflow", "hidden");
42132 this.el.setHeight(this.growMin);
42135 //console.log('onrender' + this.getId() );
42136 Roo.form.FCKeditor.editors[this.getId()] = this;
42139 this.replaceTextarea() ;
42143 getEditor : function() {
42144 return this.fckEditor;
42147 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42148 * @param {Mixed} value The value to set
42152 setValue : function(value)
42154 //console.log('setValue: ' + value);
42156 if(typeof(value) == 'undefined') { // not sure why this is happending...
42159 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42161 //if(!this.el || !this.getEditor()) {
42162 // this.value = value;
42163 //this.setValue.defer(100,this,[value]);
42167 if(!this.getEditor()) {
42171 this.getEditor().SetData(value);
42178 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42179 * @return {Mixed} value The field value
42181 getValue : function()
42184 if (this.frame && this.frame.dom.style.display == 'none') {
42185 return Roo.form.FCKeditor.superclass.getValue.call(this);
42188 if(!this.el || !this.getEditor()) {
42190 // this.getValue.defer(100,this);
42195 var value=this.getEditor().GetData();
42196 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42197 return Roo.form.FCKeditor.superclass.getValue.call(this);
42203 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42204 * @return {Mixed} value The field value
42206 getRawValue : function()
42208 if (this.frame && this.frame.dom.style.display == 'none') {
42209 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42212 if(!this.el || !this.getEditor()) {
42213 //this.getRawValue.defer(100,this);
42220 var value=this.getEditor().GetData();
42221 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42222 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42226 setSize : function(w,h) {
42230 //if (this.frame && this.frame.dom.style.display == 'none') {
42231 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42234 //if(!this.el || !this.getEditor()) {
42235 // this.setSize.defer(100,this, [w,h]);
42241 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42243 this.frame.dom.setAttribute('width', w);
42244 this.frame.dom.setAttribute('height', h);
42245 this.frame.setSize(w,h);
42249 toggleSourceEdit : function(value) {
42253 this.el.dom.style.display = value ? '' : 'none';
42254 this.frame.dom.style.display = value ? 'none' : '';
42259 focus: function(tag)
42261 if (this.frame.dom.style.display == 'none') {
42262 return Roo.form.FCKeditor.superclass.focus.call(this);
42264 if(!this.el || !this.getEditor()) {
42265 this.focus.defer(100,this, [tag]);
42272 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42273 this.getEditor().Focus();
42275 if (!this.getEditor().Selection.GetSelection()) {
42276 this.focus.defer(100,this, [tag]);
42281 var r = this.getEditor().EditorDocument.createRange();
42282 r.setStart(tgs[0],0);
42283 r.setEnd(tgs[0],0);
42284 this.getEditor().Selection.GetSelection().removeAllRanges();
42285 this.getEditor().Selection.GetSelection().addRange(r);
42286 this.getEditor().Focus();
42293 replaceTextarea : function()
42295 if ( document.getElementById( this.getId() + '___Frame' ) )
42297 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42299 // We must check the elements firstly using the Id and then the name.
42300 var oTextarea = document.getElementById( this.getId() );
42302 var colElementsByName = document.getElementsByName( this.getId() ) ;
42304 oTextarea.style.display = 'none' ;
42306 if ( oTextarea.tabIndex ) {
42307 this.TabIndex = oTextarea.tabIndex ;
42310 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42311 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42312 this.frame = Roo.get(this.getId() + '___Frame')
42315 _getConfigHtml : function()
42319 for ( var o in this.fckconfig ) {
42320 sConfig += sConfig.length > 0 ? '&' : '';
42321 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42324 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42328 _getIFrameHtml : function()
42330 var sFile = 'fckeditor.html' ;
42331 /* no idea what this is about..
42334 if ( (/fcksource=true/i).test( window.top.location.search ) )
42335 sFile = 'fckeditor.original.html' ;
42340 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42341 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42344 var html = '<iframe id="' + this.getId() +
42345 '___Frame" src="' + sLink +
42346 '" width="' + this.width +
42347 '" height="' + this.height + '"' +
42348 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42349 ' frameborder="0" scrolling="no"></iframe>' ;
42354 _insertHtmlBefore : function( html, element )
42356 if ( element.insertAdjacentHTML ) {
42358 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42360 var oRange = document.createRange() ;
42361 oRange.setStartBefore( element ) ;
42362 var oFragment = oRange.createContextualFragment( html );
42363 element.parentNode.insertBefore( oFragment, element ) ;
42376 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42378 function FCKeditor_OnComplete(editorInstance){
42379 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42380 f.fckEditor = editorInstance;
42381 //console.log("loaded");
42382 f.fireEvent('editorinit', f, editorInstance);
42402 //<script type="text/javascript">
42404 * @class Roo.form.GridField
42405 * @extends Roo.form.Field
42406 * Embed a grid (or editable grid into a form)
42409 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42411 * xgrid.store = Roo.data.Store
42412 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42413 * xgrid.store.reader = Roo.data.JsonReader
42417 * Creates a new GridField
42418 * @param {Object} config Configuration options
42420 Roo.form.GridField = function(config){
42421 Roo.form.GridField.superclass.constructor.call(this, config);
42425 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42427 * @cfg {Number} width - used to restrict width of grid..
42431 * @cfg {Number} height - used to restrict height of grid..
42435 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42441 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42442 * {tag: "input", type: "checkbox", autocomplete: "off"})
42444 // defaultAutoCreate : { tag: 'div' },
42445 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42447 * @cfg {String} addTitle Text to include for adding a title.
42451 onResize : function(){
42452 Roo.form.Field.superclass.onResize.apply(this, arguments);
42455 initEvents : function(){
42456 // Roo.form.Checkbox.superclass.initEvents.call(this);
42457 // has no events...
42462 getResizeEl : function(){
42466 getPositionEl : function(){
42471 onRender : function(ct, position){
42473 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42474 var style = this.style;
42477 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42478 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42479 this.viewEl = this.wrap.createChild({ tag: 'div' });
42481 this.viewEl.applyStyles(style);
42484 this.viewEl.setWidth(this.width);
42487 this.viewEl.setHeight(this.height);
42489 //if(this.inputValue !== undefined){
42490 //this.setValue(this.value);
42493 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42496 this.grid.render();
42497 this.grid.getDataSource().on('remove', this.refreshValue, this);
42498 this.grid.getDataSource().on('update', this.refreshValue, this);
42499 this.grid.on('afteredit', this.refreshValue, this);
42505 * Sets the value of the item.
42506 * @param {String} either an object or a string..
42508 setValue : function(v){
42510 v = v || []; // empty set..
42511 // this does not seem smart - it really only affects memoryproxy grids..
42512 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42513 var ds = this.grid.getDataSource();
42514 // assumes a json reader..
42516 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42517 ds.loadData( data);
42519 Roo.form.GridField.superclass.setValue.call(this, v);
42520 this.refreshValue();
42521 // should load data in the grid really....
42525 refreshValue: function() {
42527 this.grid.getDataSource().each(function(r) {
42530 this.el.dom.value = Roo.encode(val);
42538 * Ext JS Library 1.1.1
42539 * Copyright(c) 2006-2007, Ext JS, LLC.
42541 * Originally Released Under LGPL - original licence link has changed is not relivant.
42544 * <script type="text/javascript">
42547 * @class Roo.form.DisplayField
42548 * @extends Roo.form.Field
42549 * A generic Field to display non-editable data.
42551 * Creates a new Display Field item.
42552 * @param {Object} config Configuration options
42554 Roo.form.DisplayField = function(config){
42555 Roo.form.DisplayField.superclass.constructor.call(this, config);
42559 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42560 inputType: 'hidden',
42566 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42568 focusClass : undefined,
42570 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42572 fieldClass: 'x-form-field',
42575 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42577 valueRenderer: undefined,
42581 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42582 * {tag: "input", type: "checkbox", autocomplete: "off"})
42585 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42587 onResize : function(){
42588 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42592 initEvents : function(){
42593 // Roo.form.Checkbox.superclass.initEvents.call(this);
42594 // has no events...
42599 getResizeEl : function(){
42603 getPositionEl : function(){
42608 onRender : function(ct, position){
42610 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42611 //if(this.inputValue !== undefined){
42612 this.wrap = this.el.wrap();
42614 this.viewEl = this.wrap.createChild({ tag: 'div'});
42616 if (this.bodyStyle) {
42617 this.viewEl.applyStyles(this.bodyStyle);
42619 //this.viewEl.setStyle('padding', '2px');
42621 this.setValue(this.value);
42626 initValue : Roo.emptyFn,
42631 onClick : function(){
42636 * Sets the checked state of the checkbox.
42637 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42639 setValue : function(v){
42641 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42642 // this might be called before we have a dom element..
42643 if (!this.viewEl) {
42646 this.viewEl.dom.innerHTML = html;
42647 Roo.form.DisplayField.superclass.setValue.call(this, v);
42650 });//<script type="text/javasscript">
42654 * @class Roo.DDView
42655 * A DnD enabled version of Roo.View.
42656 * @param {Element/String} container The Element in which to create the View.
42657 * @param {String} tpl The template string used to create the markup for each element of the View
42658 * @param {Object} config The configuration properties. These include all the config options of
42659 * {@link Roo.View} plus some specific to this class.<br>
42661 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42662 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42664 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42665 .x-view-drag-insert-above {
42666 border-top:1px dotted #3366cc;
42668 .x-view-drag-insert-below {
42669 border-bottom:1px dotted #3366cc;
42675 Roo.DDView = function(container, tpl, config) {
42676 Roo.DDView.superclass.constructor.apply(this, arguments);
42677 this.getEl().setStyle("outline", "0px none");
42678 this.getEl().unselectable();
42679 if (this.dragGroup) {
42680 this.setDraggable(this.dragGroup.split(","));
42682 if (this.dropGroup) {
42683 this.setDroppable(this.dropGroup.split(","));
42685 if (this.deletable) {
42686 this.setDeletable();
42688 this.isDirtyFlag = false;
42694 Roo.extend(Roo.DDView, Roo.View, {
42695 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42696 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42697 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42698 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42702 reset: Roo.emptyFn,
42704 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42706 validate: function() {
42710 destroy: function() {
42711 this.purgeListeners();
42712 this.getEl.removeAllListeners();
42713 this.getEl().remove();
42714 if (this.dragZone) {
42715 if (this.dragZone.destroy) {
42716 this.dragZone.destroy();
42719 if (this.dropZone) {
42720 if (this.dropZone.destroy) {
42721 this.dropZone.destroy();
42726 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
42727 getName: function() {
42731 /** Loads the View from a JSON string representing the Records to put into the Store. */
42732 setValue: function(v) {
42734 throw "DDView.setValue(). DDView must be constructed with a valid Store";
42737 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
42738 this.store.proxy = new Roo.data.MemoryProxy(data);
42742 /** @return {String} a parenthesised list of the ids of the Records in the View. */
42743 getValue: function() {
42745 this.store.each(function(rec) {
42746 result += rec.id + ',';
42748 return result.substr(0, result.length - 1) + ')';
42751 getIds: function() {
42752 var i = 0, result = new Array(this.store.getCount());
42753 this.store.each(function(rec) {
42754 result[i++] = rec.id;
42759 isDirty: function() {
42760 return this.isDirtyFlag;
42764 * Part of the Roo.dd.DropZone interface. If no target node is found, the
42765 * whole Element becomes the target, and this causes the drop gesture to append.
42767 getTargetFromEvent : function(e) {
42768 var target = e.getTarget();
42769 while ((target !== null) && (target.parentNode != this.el.dom)) {
42770 target = target.parentNode;
42773 target = this.el.dom.lastChild || this.el.dom;
42779 * Create the drag data which consists of an object which has the property "ddel" as
42780 * the drag proxy element.
42782 getDragData : function(e) {
42783 var target = this.findItemFromChild(e.getTarget());
42785 this.handleSelection(e);
42786 var selNodes = this.getSelectedNodes();
42789 copy: this.copy || (this.allowCopy && e.ctrlKey),
42793 var selectedIndices = this.getSelectedIndexes();
42794 for (var i = 0; i < selectedIndices.length; i++) {
42795 dragData.records.push(this.store.getAt(selectedIndices[i]));
42797 if (selNodes.length == 1) {
42798 dragData.ddel = target.cloneNode(true); // the div element
42800 var div = document.createElement('div'); // create the multi element drag "ghost"
42801 div.className = 'multi-proxy';
42802 for (var i = 0, len = selNodes.length; i < len; i++) {
42803 div.appendChild(selNodes[i].cloneNode(true));
42805 dragData.ddel = div;
42807 //console.log(dragData)
42808 //console.log(dragData.ddel.innerHTML)
42811 //console.log('nodragData')
42815 /** Specify to which ddGroup items in this DDView may be dragged. */
42816 setDraggable: function(ddGroup) {
42817 if (ddGroup instanceof Array) {
42818 Roo.each(ddGroup, this.setDraggable, this);
42821 if (this.dragZone) {
42822 this.dragZone.addToGroup(ddGroup);
42824 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
42825 containerScroll: true,
42829 // Draggability implies selection. DragZone's mousedown selects the element.
42830 if (!this.multiSelect) { this.singleSelect = true; }
42832 // Wire the DragZone's handlers up to methods in *this*
42833 this.dragZone.getDragData = this.getDragData.createDelegate(this);
42837 /** Specify from which ddGroup this DDView accepts drops. */
42838 setDroppable: function(ddGroup) {
42839 if (ddGroup instanceof Array) {
42840 Roo.each(ddGroup, this.setDroppable, this);
42843 if (this.dropZone) {
42844 this.dropZone.addToGroup(ddGroup);
42846 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
42847 containerScroll: true,
42851 // Wire the DropZone's handlers up to methods in *this*
42852 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
42853 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
42854 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
42855 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
42856 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
42860 /** Decide whether to drop above or below a View node. */
42861 getDropPoint : function(e, n, dd){
42862 if (n == this.el.dom) { return "above"; }
42863 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
42864 var c = t + (b - t) / 2;
42865 var y = Roo.lib.Event.getPageY(e);
42873 onNodeEnter : function(n, dd, e, data){
42877 onNodeOver : function(n, dd, e, data){
42878 var pt = this.getDropPoint(e, n, dd);
42879 // set the insert point style on the target node
42880 var dragElClass = this.dropNotAllowed;
42883 if (pt == "above"){
42884 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
42885 targetElClass = "x-view-drag-insert-above";
42887 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
42888 targetElClass = "x-view-drag-insert-below";
42890 if (this.lastInsertClass != targetElClass){
42891 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
42892 this.lastInsertClass = targetElClass;
42895 return dragElClass;
42898 onNodeOut : function(n, dd, e, data){
42899 this.removeDropIndicators(n);
42902 onNodeDrop : function(n, dd, e, data){
42903 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
42906 var pt = this.getDropPoint(e, n, dd);
42907 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
42908 if (pt == "below") { insertAt++; }
42909 for (var i = 0; i < data.records.length; i++) {
42910 var r = data.records[i];
42911 var dup = this.store.getById(r.id);
42912 if (dup && (dd != this.dragZone)) {
42913 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
42916 this.store.insert(insertAt++, r.copy());
42918 data.source.isDirtyFlag = true;
42920 this.store.insert(insertAt++, r);
42922 this.isDirtyFlag = true;
42925 this.dragZone.cachedTarget = null;
42929 removeDropIndicators : function(n){
42931 Roo.fly(n).removeClass([
42932 "x-view-drag-insert-above",
42933 "x-view-drag-insert-below"]);
42934 this.lastInsertClass = "_noclass";
42939 * Utility method. Add a delete option to the DDView's context menu.
42940 * @param {String} imageUrl The URL of the "delete" icon image.
42942 setDeletable: function(imageUrl) {
42943 if (!this.singleSelect && !this.multiSelect) {
42944 this.singleSelect = true;
42946 var c = this.getContextMenu();
42947 this.contextMenu.on("itemclick", function(item) {
42950 this.remove(this.getSelectedIndexes());
42954 this.contextMenu.add({
42961 /** Return the context menu for this DDView. */
42962 getContextMenu: function() {
42963 if (!this.contextMenu) {
42964 // Create the View's context menu
42965 this.contextMenu = new Roo.menu.Menu({
42966 id: this.id + "-contextmenu"
42968 this.el.on("contextmenu", this.showContextMenu, this);
42970 return this.contextMenu;
42973 disableContextMenu: function() {
42974 if (this.contextMenu) {
42975 this.el.un("contextmenu", this.showContextMenu, this);
42979 showContextMenu: function(e, item) {
42980 item = this.findItemFromChild(e.getTarget());
42983 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
42984 this.contextMenu.showAt(e.getXY());
42989 * Remove {@link Roo.data.Record}s at the specified indices.
42990 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42992 remove: function(selectedIndices) {
42993 selectedIndices = [].concat(selectedIndices);
42994 for (var i = 0; i < selectedIndices.length; i++) {
42995 var rec = this.store.getAt(selectedIndices[i]);
42996 this.store.remove(rec);
43001 * Double click fires the event, but also, if this is draggable, and there is only one other
43002 * related DropZone, it transfers the selected node.
43004 onDblClick : function(e){
43005 var item = this.findItemFromChild(e.getTarget());
43007 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
43010 if (this.dragGroup) {
43011 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
43012 while (targets.indexOf(this.dropZone) > -1) {
43013 targets.remove(this.dropZone);
43015 if (targets.length == 1) {
43016 this.dragZone.cachedTarget = null;
43017 var el = Roo.get(targets[0].getEl());
43018 var box = el.getBox(true);
43019 targets[0].onNodeDrop(el.dom, {
43021 xy: [box.x, box.y + box.height - 1]
43022 }, null, this.getDragData(e));
43028 handleSelection: function(e) {
43029 this.dragZone.cachedTarget = null;
43030 var item = this.findItemFromChild(e.getTarget());
43032 this.clearSelections(true);
43035 if (item && (this.multiSelect || this.singleSelect)){
43036 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
43037 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
43038 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
43039 this.unselect(item);
43041 this.select(item, this.multiSelect && e.ctrlKey);
43042 this.lastSelection = item;
43047 onItemClick : function(item, index, e){
43048 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43054 unselect : function(nodeInfo, suppressEvent){
43055 var node = this.getNode(nodeInfo);
43056 if(node && this.isSelected(node)){
43057 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43058 Roo.fly(node).removeClass(this.selectedClass);
43059 this.selections.remove(node);
43060 if(!suppressEvent){
43061 this.fireEvent("selectionchange", this, this.selections);
43069 * Ext JS Library 1.1.1
43070 * Copyright(c) 2006-2007, Ext JS, LLC.
43072 * Originally Released Under LGPL - original licence link has changed is not relivant.
43075 * <script type="text/javascript">
43079 * @class Roo.LayoutManager
43080 * @extends Roo.util.Observable
43081 * Base class for layout managers.
43083 Roo.LayoutManager = function(container, config){
43084 Roo.LayoutManager.superclass.constructor.call(this);
43085 this.el = Roo.get(container);
43086 // ie scrollbar fix
43087 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43088 document.body.scroll = "no";
43089 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43090 this.el.position('relative');
43092 this.id = this.el.id;
43093 this.el.addClass("x-layout-container");
43094 /** false to disable window resize monitoring @type Boolean */
43095 this.monitorWindowResize = true;
43100 * Fires when a layout is performed.
43101 * @param {Roo.LayoutManager} this
43105 * @event regionresized
43106 * Fires when the user resizes a region.
43107 * @param {Roo.LayoutRegion} region The resized region
43108 * @param {Number} newSize The new size (width for east/west, height for north/south)
43110 "regionresized" : true,
43112 * @event regioncollapsed
43113 * Fires when a region is collapsed.
43114 * @param {Roo.LayoutRegion} region The collapsed region
43116 "regioncollapsed" : true,
43118 * @event regionexpanded
43119 * Fires when a region is expanded.
43120 * @param {Roo.LayoutRegion} region The expanded region
43122 "regionexpanded" : true
43124 this.updating = false;
43125 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43128 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43130 * Returns true if this layout is currently being updated
43131 * @return {Boolean}
43133 isUpdating : function(){
43134 return this.updating;
43138 * Suspend the LayoutManager from doing auto-layouts while
43139 * making multiple add or remove calls
43141 beginUpdate : function(){
43142 this.updating = true;
43146 * Restore auto-layouts and optionally disable the manager from performing a layout
43147 * @param {Boolean} noLayout true to disable a layout update
43149 endUpdate : function(noLayout){
43150 this.updating = false;
43156 layout: function(){
43160 onRegionResized : function(region, newSize){
43161 this.fireEvent("regionresized", region, newSize);
43165 onRegionCollapsed : function(region){
43166 this.fireEvent("regioncollapsed", region);
43169 onRegionExpanded : function(region){
43170 this.fireEvent("regionexpanded", region);
43174 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43175 * performs box-model adjustments.
43176 * @return {Object} The size as an object {width: (the width), height: (the height)}
43178 getViewSize : function(){
43180 if(this.el.dom != document.body){
43181 size = this.el.getSize();
43183 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43185 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43186 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43191 * Returns the Element this layout is bound to.
43192 * @return {Roo.Element}
43194 getEl : function(){
43199 * Returns the specified region.
43200 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43201 * @return {Roo.LayoutRegion}
43203 getRegion : function(target){
43204 return this.regions[target.toLowerCase()];
43207 onWindowResize : function(){
43208 if(this.monitorWindowResize){
43214 * Ext JS Library 1.1.1
43215 * Copyright(c) 2006-2007, Ext JS, LLC.
43217 * Originally Released Under LGPL - original licence link has changed is not relivant.
43220 * <script type="text/javascript">
43223 * @class Roo.BorderLayout
43224 * @extends Roo.LayoutManager
43225 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43226 * please see: <br><br>
43227 * <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>
43228 * <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>
43231 var layout = new Roo.BorderLayout(document.body, {
43265 preferredTabWidth: 150
43270 var CP = Roo.ContentPanel;
43272 layout.beginUpdate();
43273 layout.add("north", new CP("north", "North"));
43274 layout.add("south", new CP("south", {title: "South", closable: true}));
43275 layout.add("west", new CP("west", {title: "West"}));
43276 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43277 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43278 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43279 layout.getRegion("center").showPanel("center1");
43280 layout.endUpdate();
43283 <b>The container the layout is rendered into can be either the body element or any other element.
43284 If it is not the body element, the container needs to either be an absolute positioned element,
43285 or you will need to add "position:relative" to the css of the container. You will also need to specify
43286 the container size if it is not the body element.</b>
43289 * Create a new BorderLayout
43290 * @param {String/HTMLElement/Element} container The container this layout is bound to
43291 * @param {Object} config Configuration options
43293 Roo.BorderLayout = function(container, config){
43294 config = config || {};
43295 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43296 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43297 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43298 var target = this.factory.validRegions[i];
43299 if(config[target]){
43300 this.addRegion(target, config[target]);
43305 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43307 * Creates and adds a new region if it doesn't already exist.
43308 * @param {String} target The target region key (north, south, east, west or center).
43309 * @param {Object} config The regions config object
43310 * @return {BorderLayoutRegion} The new region
43312 addRegion : function(target, config){
43313 if(!this.regions[target]){
43314 var r = this.factory.create(target, this, config);
43315 this.bindRegion(target, r);
43317 return this.regions[target];
43321 bindRegion : function(name, r){
43322 this.regions[name] = r;
43323 r.on("visibilitychange", this.layout, this);
43324 r.on("paneladded", this.layout, this);
43325 r.on("panelremoved", this.layout, this);
43326 r.on("invalidated", this.layout, this);
43327 r.on("resized", this.onRegionResized, this);
43328 r.on("collapsed", this.onRegionCollapsed, this);
43329 r.on("expanded", this.onRegionExpanded, this);
43333 * Performs a layout update.
43335 layout : function(){
43336 if(this.updating) return;
43337 var size = this.getViewSize();
43338 var w = size.width;
43339 var h = size.height;
43344 //var x = 0, y = 0;
43346 var rs = this.regions;
43347 var north = rs["north"];
43348 var south = rs["south"];
43349 var west = rs["west"];
43350 var east = rs["east"];
43351 var center = rs["center"];
43352 //if(this.hideOnLayout){ // not supported anymore
43353 //c.el.setStyle("display", "none");
43355 if(north && north.isVisible()){
43356 var b = north.getBox();
43357 var m = north.getMargins();
43358 b.width = w - (m.left+m.right);
43361 centerY = b.height + b.y + m.bottom;
43362 centerH -= centerY;
43363 north.updateBox(this.safeBox(b));
43365 if(south && south.isVisible()){
43366 var b = south.getBox();
43367 var m = south.getMargins();
43368 b.width = w - (m.left+m.right);
43370 var totalHeight = (b.height + m.top + m.bottom);
43371 b.y = h - totalHeight + m.top;
43372 centerH -= totalHeight;
43373 south.updateBox(this.safeBox(b));
43375 if(west && west.isVisible()){
43376 var b = west.getBox();
43377 var m = west.getMargins();
43378 b.height = centerH - (m.top+m.bottom);
43380 b.y = centerY + m.top;
43381 var totalWidth = (b.width + m.left + m.right);
43382 centerX += totalWidth;
43383 centerW -= totalWidth;
43384 west.updateBox(this.safeBox(b));
43386 if(east && east.isVisible()){
43387 var b = east.getBox();
43388 var m = east.getMargins();
43389 b.height = centerH - (m.top+m.bottom);
43390 var totalWidth = (b.width + m.left + m.right);
43391 b.x = w - totalWidth + m.left;
43392 b.y = centerY + m.top;
43393 centerW -= totalWidth;
43394 east.updateBox(this.safeBox(b));
43397 var m = center.getMargins();
43399 x: centerX + m.left,
43400 y: centerY + m.top,
43401 width: centerW - (m.left+m.right),
43402 height: centerH - (m.top+m.bottom)
43404 //if(this.hideOnLayout){
43405 //center.el.setStyle("display", "block");
43407 center.updateBox(this.safeBox(centerBox));
43410 this.fireEvent("layout", this);
43414 safeBox : function(box){
43415 box.width = Math.max(0, box.width);
43416 box.height = Math.max(0, box.height);
43421 * Adds a ContentPanel (or subclass) to this layout.
43422 * @param {String} target The target region key (north, south, east, west or center).
43423 * @param {Roo.ContentPanel} panel The panel to add
43424 * @return {Roo.ContentPanel} The added panel
43426 add : function(target, panel){
43428 target = target.toLowerCase();
43429 return this.regions[target].add(panel);
43433 * Remove a ContentPanel (or subclass) to this layout.
43434 * @param {String} target The target region key (north, south, east, west or center).
43435 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43436 * @return {Roo.ContentPanel} The removed panel
43438 remove : function(target, panel){
43439 target = target.toLowerCase();
43440 return this.regions[target].remove(panel);
43444 * Searches all regions for a panel with the specified id
43445 * @param {String} panelId
43446 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43448 findPanel : function(panelId){
43449 var rs = this.regions;
43450 for(var target in rs){
43451 if(typeof rs[target] != "function"){
43452 var p = rs[target].getPanel(panelId);
43462 * Searches all regions for a panel with the specified id and activates (shows) it.
43463 * @param {String/ContentPanel} panelId The panels id or the panel itself
43464 * @return {Roo.ContentPanel} The shown panel or null
43466 showPanel : function(panelId) {
43467 var rs = this.regions;
43468 for(var target in rs){
43469 var r = rs[target];
43470 if(typeof r != "function"){
43471 if(r.hasPanel(panelId)){
43472 return r.showPanel(panelId);
43480 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43481 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43483 restoreState : function(provider){
43485 provider = Roo.state.Manager;
43487 var sm = new Roo.LayoutStateManager();
43488 sm.init(this, provider);
43492 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43493 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43494 * a valid ContentPanel config object. Example:
43496 // Create the main layout
43497 var layout = new Roo.BorderLayout('main-ct', {
43508 // Create and add multiple ContentPanels at once via configs
43511 id: 'source-files',
43513 title:'Ext Source Files',
43526 * @param {Object} regions An object containing ContentPanel configs by region name
43528 batchAdd : function(regions){
43529 this.beginUpdate();
43530 for(var rname in regions){
43531 var lr = this.regions[rname];
43533 this.addTypedPanels(lr, regions[rname]);
43540 addTypedPanels : function(lr, ps){
43541 if(typeof ps == 'string'){
43542 lr.add(new Roo.ContentPanel(ps));
43544 else if(ps instanceof Array){
43545 for(var i =0, len = ps.length; i < len; i++){
43546 this.addTypedPanels(lr, ps[i]);
43549 else if(!ps.events){ // raw config?
43551 delete ps.el; // prevent conflict
43552 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43554 else { // panel object assumed!
43559 * Adds a xtype elements to the layout.
43563 xtype : 'ContentPanel',
43570 xtype : 'NestedLayoutPanel',
43576 items : [ ... list of content panels or nested layout panels.. ]
43580 * @param {Object} cfg Xtype definition of item to add.
43582 addxtype : function(cfg)
43584 // basically accepts a pannel...
43585 // can accept a layout region..!?!?
43586 // console.log('BorderLayout add ' + cfg.xtype)
43588 if (!cfg.xtype.match(/Panel$/)) {
43592 var region = cfg.region;
43598 xitems = cfg.items;
43605 case 'ContentPanel': // ContentPanel (el, cfg)
43606 case 'ScrollPanel': // ContentPanel (el, cfg)
43607 if(cfg.autoCreate) {
43608 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43610 var el = this.el.createChild();
43611 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43614 this.add(region, ret);
43618 case 'TreePanel': // our new panel!
43619 cfg.el = this.el.createChild();
43620 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43621 this.add(region, ret);
43624 case 'NestedLayoutPanel':
43625 // create a new Layout (which is a Border Layout...
43626 var el = this.el.createChild();
43627 var clayout = cfg.layout;
43629 clayout.items = clayout.items || [];
43630 // replace this exitems with the clayout ones..
43631 xitems = clayout.items;
43634 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43635 cfg.background = false;
43637 var layout = new Roo.BorderLayout(el, clayout);
43639 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43640 //console.log('adding nested layout panel ' + cfg.toSource());
43641 this.add(region, ret);
43647 // needs grid and region
43649 //var el = this.getRegion(region).el.createChild();
43650 var el = this.el.createChild();
43651 // create the grid first...
43653 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43655 if (region == 'center' && this.active ) {
43656 cfg.background = false;
43658 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43660 this.add(region, ret);
43661 if (cfg.background) {
43662 ret.on('activate', function(gp) {
43663 if (!gp.grid.rendered) {
43676 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43678 // GridPanel (grid, cfg)
43681 this.beginUpdate();
43683 Roo.each(xitems, function(i) {
43693 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43694 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43695 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43696 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43699 var CP = Roo.ContentPanel;
43701 var layout = Roo.BorderLayout.create({
43705 panels: [new CP("north", "North")]
43714 panels: [new CP("west", {title: "West"})]
43723 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
43732 panels: [new CP("south", {title: "South", closable: true})]
43739 preferredTabWidth: 150,
43741 new CP("center1", {title: "Close Me", closable: true}),
43742 new CP("center2", {title: "Center Panel", closable: false})
43747 layout.getRegion("center").showPanel("center1");
43752 Roo.BorderLayout.create = function(config, targetEl){
43753 var layout = new Roo.BorderLayout(targetEl || document.body, config);
43754 layout.beginUpdate();
43755 var regions = Roo.BorderLayout.RegionFactory.validRegions;
43756 for(var j = 0, jlen = regions.length; j < jlen; j++){
43757 var lr = regions[j];
43758 if(layout.regions[lr] && config[lr].panels){
43759 var r = layout.regions[lr];
43760 var ps = config[lr].panels;
43761 layout.addTypedPanels(r, ps);
43764 layout.endUpdate();
43769 Roo.BorderLayout.RegionFactory = {
43771 validRegions : ["north","south","east","west","center"],
43774 create : function(target, mgr, config){
43775 target = target.toLowerCase();
43776 if(config.lightweight || config.basic){
43777 return new Roo.BasicLayoutRegion(mgr, config, target);
43781 return new Roo.NorthLayoutRegion(mgr, config);
43783 return new Roo.SouthLayoutRegion(mgr, config);
43785 return new Roo.EastLayoutRegion(mgr, config);
43787 return new Roo.WestLayoutRegion(mgr, config);
43789 return new Roo.CenterLayoutRegion(mgr, config);
43791 throw 'Layout region "'+target+'" not supported.';
43795 * Ext JS Library 1.1.1
43796 * Copyright(c) 2006-2007, Ext JS, LLC.
43798 * Originally Released Under LGPL - original licence link has changed is not relivant.
43801 * <script type="text/javascript">
43805 * @class Roo.BasicLayoutRegion
43806 * @extends Roo.util.Observable
43807 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
43808 * and does not have a titlebar, tabs or any other features. All it does is size and position
43809 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
43811 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
43813 this.position = pos;
43816 * @scope Roo.BasicLayoutRegion
43820 * @event beforeremove
43821 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
43822 * @param {Roo.LayoutRegion} this
43823 * @param {Roo.ContentPanel} panel The panel
43824 * @param {Object} e The cancel event object
43826 "beforeremove" : true,
43828 * @event invalidated
43829 * Fires when the layout for this region is changed.
43830 * @param {Roo.LayoutRegion} this
43832 "invalidated" : true,
43834 * @event visibilitychange
43835 * Fires when this region is shown or hidden
43836 * @param {Roo.LayoutRegion} this
43837 * @param {Boolean} visibility true or false
43839 "visibilitychange" : true,
43841 * @event paneladded
43842 * Fires when a panel is added.
43843 * @param {Roo.LayoutRegion} this
43844 * @param {Roo.ContentPanel} panel The panel
43846 "paneladded" : true,
43848 * @event panelremoved
43849 * Fires when a panel is removed.
43850 * @param {Roo.LayoutRegion} this
43851 * @param {Roo.ContentPanel} panel The panel
43853 "panelremoved" : true,
43856 * Fires when this region is collapsed.
43857 * @param {Roo.LayoutRegion} this
43859 "collapsed" : true,
43862 * Fires when this region is expanded.
43863 * @param {Roo.LayoutRegion} this
43868 * Fires when this region is slid into view.
43869 * @param {Roo.LayoutRegion} this
43871 "slideshow" : true,
43874 * Fires when this region slides out of view.
43875 * @param {Roo.LayoutRegion} this
43877 "slidehide" : true,
43879 * @event panelactivated
43880 * Fires when a panel is activated.
43881 * @param {Roo.LayoutRegion} this
43882 * @param {Roo.ContentPanel} panel The activated panel
43884 "panelactivated" : true,
43887 * Fires when the user resizes this region.
43888 * @param {Roo.LayoutRegion} this
43889 * @param {Number} newSize The new size (width for east/west, height for north/south)
43893 /** A collection of panels in this region. @type Roo.util.MixedCollection */
43894 this.panels = new Roo.util.MixedCollection();
43895 this.panels.getKey = this.getPanelId.createDelegate(this);
43897 this.activePanel = null;
43898 // ensure listeners are added...
43900 if (config.listeners || config.events) {
43901 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
43902 listeners : config.listeners || {},
43903 events : config.events || {}
43907 if(skipConfig !== true){
43908 this.applyConfig(config);
43912 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
43913 getPanelId : function(p){
43917 applyConfig : function(config){
43918 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43919 this.config = config;
43924 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
43925 * the width, for horizontal (north, south) the height.
43926 * @param {Number} newSize The new width or height
43928 resizeTo : function(newSize){
43929 var el = this.el ? this.el :
43930 (this.activePanel ? this.activePanel.getEl() : null);
43932 switch(this.position){
43935 el.setWidth(newSize);
43936 this.fireEvent("resized", this, newSize);
43940 el.setHeight(newSize);
43941 this.fireEvent("resized", this, newSize);
43947 getBox : function(){
43948 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
43951 getMargins : function(){
43952 return this.margins;
43955 updateBox : function(box){
43957 var el = this.activePanel.getEl();
43958 el.dom.style.left = box.x + "px";
43959 el.dom.style.top = box.y + "px";
43960 this.activePanel.setSize(box.width, box.height);
43964 * Returns the container element for this region.
43965 * @return {Roo.Element}
43967 getEl : function(){
43968 return this.activePanel;
43972 * Returns true if this region is currently visible.
43973 * @return {Boolean}
43975 isVisible : function(){
43976 return this.activePanel ? true : false;
43979 setActivePanel : function(panel){
43980 panel = this.getPanel(panel);
43981 if(this.activePanel && this.activePanel != panel){
43982 this.activePanel.setActiveState(false);
43983 this.activePanel.getEl().setLeftTop(-10000,-10000);
43985 this.activePanel = panel;
43986 panel.setActiveState(true);
43988 panel.setSize(this.box.width, this.box.height);
43990 this.fireEvent("panelactivated", this, panel);
43991 this.fireEvent("invalidated");
43995 * Show the specified panel.
43996 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43997 * @return {Roo.ContentPanel} The shown panel or null
43999 showPanel : function(panel){
44000 if(panel = this.getPanel(panel)){
44001 this.setActivePanel(panel);
44007 * Get the active panel for this region.
44008 * @return {Roo.ContentPanel} The active panel or null
44010 getActivePanel : function(){
44011 return this.activePanel;
44015 * Add the passed ContentPanel(s)
44016 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44017 * @return {Roo.ContentPanel} The panel added (if only one was added)
44019 add : function(panel){
44020 if(arguments.length > 1){
44021 for(var i = 0, len = arguments.length; i < len; i++) {
44022 this.add(arguments[i]);
44026 if(this.hasPanel(panel)){
44027 this.showPanel(panel);
44030 var el = panel.getEl();
44031 if(el.dom.parentNode != this.mgr.el.dom){
44032 this.mgr.el.dom.appendChild(el.dom);
44034 if(panel.setRegion){
44035 panel.setRegion(this);
44037 this.panels.add(panel);
44038 el.setStyle("position", "absolute");
44039 if(!panel.background){
44040 this.setActivePanel(panel);
44041 if(this.config.initialSize && this.panels.getCount()==1){
44042 this.resizeTo(this.config.initialSize);
44045 this.fireEvent("paneladded", this, panel);
44050 * Returns true if the panel is in this region.
44051 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44052 * @return {Boolean}
44054 hasPanel : function(panel){
44055 if(typeof panel == "object"){ // must be panel obj
44056 panel = panel.getId();
44058 return this.getPanel(panel) ? true : false;
44062 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44063 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44064 * @param {Boolean} preservePanel Overrides the config preservePanel option
44065 * @return {Roo.ContentPanel} The panel that was removed
44067 remove : function(panel, preservePanel){
44068 panel = this.getPanel(panel);
44073 this.fireEvent("beforeremove", this, panel, e);
44074 if(e.cancel === true){
44077 var panelId = panel.getId();
44078 this.panels.removeKey(panelId);
44083 * Returns the panel specified or null if it's not in this region.
44084 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44085 * @return {Roo.ContentPanel}
44087 getPanel : function(id){
44088 if(typeof id == "object"){ // must be panel obj
44091 return this.panels.get(id);
44095 * Returns this regions position (north/south/east/west/center).
44098 getPosition: function(){
44099 return this.position;
44103 * Ext JS Library 1.1.1
44104 * Copyright(c) 2006-2007, Ext JS, LLC.
44106 * Originally Released Under LGPL - original licence link has changed is not relivant.
44109 * <script type="text/javascript">
44113 * @class Roo.LayoutRegion
44114 * @extends Roo.BasicLayoutRegion
44115 * This class represents a region in a layout manager.
44116 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44117 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44118 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44119 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44120 * @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})
44121 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44122 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44123 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44124 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44125 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44126 * @cfg {String} title The title for the region (overrides panel titles)
44127 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44128 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44129 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44130 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44131 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44132 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44133 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44134 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44135 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44136 * @cfg {Boolean} showPin True to show a pin button
44137 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44138 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44139 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44140 * @cfg {Number} width For East/West panels
44141 * @cfg {Number} height For North/South panels
44142 * @cfg {Boolean} split To show the splitter
44144 Roo.LayoutRegion = function(mgr, config, pos){
44145 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44146 var dh = Roo.DomHelper;
44147 /** This region's container element
44148 * @type Roo.Element */
44149 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44150 /** This region's title element
44151 * @type Roo.Element */
44153 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44154 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44155 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44157 this.titleEl.enableDisplayMode();
44158 /** This region's title text element
44159 * @type HTMLElement */
44160 this.titleTextEl = this.titleEl.dom.firstChild;
44161 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44162 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44163 this.closeBtn.enableDisplayMode();
44164 this.closeBtn.on("click", this.closeClicked, this);
44165 this.closeBtn.hide();
44167 this.createBody(config);
44168 this.visible = true;
44169 this.collapsed = false;
44171 if(config.hideWhenEmpty){
44173 this.on("paneladded", this.validateVisibility, this);
44174 this.on("panelremoved", this.validateVisibility, this);
44176 this.applyConfig(config);
44179 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44181 createBody : function(){
44182 /** This region's body element
44183 * @type Roo.Element */
44184 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44187 applyConfig : function(c){
44188 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44189 var dh = Roo.DomHelper;
44190 if(c.titlebar !== false){
44191 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44192 this.collapseBtn.on("click", this.collapse, this);
44193 this.collapseBtn.enableDisplayMode();
44195 if(c.showPin === true || this.showPin){
44196 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44197 this.stickBtn.enableDisplayMode();
44198 this.stickBtn.on("click", this.expand, this);
44199 this.stickBtn.hide();
44202 /** This region's collapsed element
44203 * @type Roo.Element */
44204 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44205 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44207 if(c.floatable !== false){
44208 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44209 this.collapsedEl.on("click", this.collapseClick, this);
44212 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44213 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44214 id: "message", unselectable: "on", style:{"float":"left"}});
44215 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44217 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44218 this.expandBtn.on("click", this.expand, this);
44220 if(this.collapseBtn){
44221 this.collapseBtn.setVisible(c.collapsible == true);
44223 this.cmargins = c.cmargins || this.cmargins ||
44224 (this.position == "west" || this.position == "east" ?
44225 {top: 0, left: 2, right:2, bottom: 0} :
44226 {top: 2, left: 0, right:0, bottom: 2});
44227 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44228 this.bottomTabs = c.tabPosition != "top";
44229 this.autoScroll = c.autoScroll || false;
44230 if(this.autoScroll){
44231 this.bodyEl.setStyle("overflow", "auto");
44233 this.bodyEl.setStyle("overflow", "hidden");
44235 //if(c.titlebar !== false){
44236 if((!c.titlebar && !c.title) || c.titlebar === false){
44237 this.titleEl.hide();
44239 this.titleEl.show();
44241 this.titleTextEl.innerHTML = c.title;
44245 this.duration = c.duration || .30;
44246 this.slideDuration = c.slideDuration || .45;
44249 this.collapse(true);
44256 * Returns true if this region is currently visible.
44257 * @return {Boolean}
44259 isVisible : function(){
44260 return this.visible;
44264 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44265 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44267 setCollapsedTitle : function(title){
44268 title = title || " ";
44269 if(this.collapsedTitleTextEl){
44270 this.collapsedTitleTextEl.innerHTML = title;
44274 getBox : function(){
44276 if(!this.collapsed){
44277 b = this.el.getBox(false, true);
44279 b = this.collapsedEl.getBox(false, true);
44284 getMargins : function(){
44285 return this.collapsed ? this.cmargins : this.margins;
44288 highlight : function(){
44289 this.el.addClass("x-layout-panel-dragover");
44292 unhighlight : function(){
44293 this.el.removeClass("x-layout-panel-dragover");
44296 updateBox : function(box){
44298 if(!this.collapsed){
44299 this.el.dom.style.left = box.x + "px";
44300 this.el.dom.style.top = box.y + "px";
44301 this.updateBody(box.width, box.height);
44303 this.collapsedEl.dom.style.left = box.x + "px";
44304 this.collapsedEl.dom.style.top = box.y + "px";
44305 this.collapsedEl.setSize(box.width, box.height);
44308 this.tabs.autoSizeTabs();
44312 updateBody : function(w, h){
44314 this.el.setWidth(w);
44315 w -= this.el.getBorderWidth("rl");
44316 if(this.config.adjustments){
44317 w += this.config.adjustments[0];
44321 this.el.setHeight(h);
44322 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44323 h -= this.el.getBorderWidth("tb");
44324 if(this.config.adjustments){
44325 h += this.config.adjustments[1];
44327 this.bodyEl.setHeight(h);
44329 h = this.tabs.syncHeight(h);
44332 if(this.panelSize){
44333 w = w !== null ? w : this.panelSize.width;
44334 h = h !== null ? h : this.panelSize.height;
44336 if(this.activePanel){
44337 var el = this.activePanel.getEl();
44338 w = w !== null ? w : el.getWidth();
44339 h = h !== null ? h : el.getHeight();
44340 this.panelSize = {width: w, height: h};
44341 this.activePanel.setSize(w, h);
44343 if(Roo.isIE && this.tabs){
44344 this.tabs.el.repaint();
44349 * Returns the container element for this region.
44350 * @return {Roo.Element}
44352 getEl : function(){
44357 * Hides this region.
44360 if(!this.collapsed){
44361 this.el.dom.style.left = "-2000px";
44364 this.collapsedEl.dom.style.left = "-2000px";
44365 this.collapsedEl.hide();
44367 this.visible = false;
44368 this.fireEvent("visibilitychange", this, false);
44372 * Shows this region if it was previously hidden.
44375 if(!this.collapsed){
44378 this.collapsedEl.show();
44380 this.visible = true;
44381 this.fireEvent("visibilitychange", this, true);
44384 closeClicked : function(){
44385 if(this.activePanel){
44386 this.remove(this.activePanel);
44390 collapseClick : function(e){
44392 e.stopPropagation();
44395 e.stopPropagation();
44401 * Collapses this region.
44402 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44404 collapse : function(skipAnim){
44405 if(this.collapsed) return;
44406 this.collapsed = true;
44408 this.split.el.hide();
44410 if(this.config.animate && skipAnim !== true){
44411 this.fireEvent("invalidated", this);
44412 this.animateCollapse();
44414 this.el.setLocation(-20000,-20000);
44416 this.collapsedEl.show();
44417 this.fireEvent("collapsed", this);
44418 this.fireEvent("invalidated", this);
44422 animateCollapse : function(){
44427 * Expands this region if it was previously collapsed.
44428 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44429 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44431 expand : function(e, skipAnim){
44432 if(e) e.stopPropagation();
44433 if(!this.collapsed || this.el.hasActiveFx()) return;
44435 this.afterSlideIn();
44438 this.collapsed = false;
44439 if(this.config.animate && skipAnim !== true){
44440 this.animateExpand();
44444 this.split.el.show();
44446 this.collapsedEl.setLocation(-2000,-2000);
44447 this.collapsedEl.hide();
44448 this.fireEvent("invalidated", this);
44449 this.fireEvent("expanded", this);
44453 animateExpand : function(){
44457 initTabs : function(){
44458 this.bodyEl.setStyle("overflow", "hidden");
44459 var ts = new Roo.TabPanel(this.bodyEl.dom, {
44460 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44461 disableTooltips: this.config.disableTabTips
44463 if(this.config.hideTabs){
44464 ts.stripWrap.setDisplayed(false);
44467 ts.resizeTabs = this.config.resizeTabs === true;
44468 ts.minTabWidth = this.config.minTabWidth || 40;
44469 ts.maxTabWidth = this.config.maxTabWidth || 250;
44470 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44471 ts.monitorResize = false;
44472 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44473 ts.bodyEl.addClass('x-layout-tabs-body');
44474 this.panels.each(this.initPanelAsTab, this);
44477 initPanelAsTab : function(panel){
44478 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44479 this.config.closeOnTab && panel.isClosable());
44480 if(panel.tabTip !== undefined){
44481 ti.setTooltip(panel.tabTip);
44483 ti.on("activate", function(){
44484 this.setActivePanel(panel);
44486 if(this.config.closeOnTab){
44487 ti.on("beforeclose", function(t, e){
44489 this.remove(panel);
44495 updatePanelTitle : function(panel, title){
44496 if(this.activePanel == panel){
44497 this.updateTitle(title);
44500 var ti = this.tabs.getTab(panel.getEl().id);
44502 if(panel.tabTip !== undefined){
44503 ti.setTooltip(panel.tabTip);
44508 updateTitle : function(title){
44509 if(this.titleTextEl && !this.config.title){
44510 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44514 setActivePanel : function(panel){
44515 panel = this.getPanel(panel);
44516 if(this.activePanel && this.activePanel != panel){
44517 this.activePanel.setActiveState(false);
44519 this.activePanel = panel;
44520 panel.setActiveState(true);
44521 if(this.panelSize){
44522 panel.setSize(this.panelSize.width, this.panelSize.height);
44525 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44527 this.updateTitle(panel.getTitle());
44529 this.fireEvent("invalidated", this);
44531 this.fireEvent("panelactivated", this, panel);
44535 * Shows the specified panel.
44536 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44537 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44539 showPanel : function(panel){
44540 if(panel = this.getPanel(panel)){
44542 var tab = this.tabs.getTab(panel.getEl().id);
44543 if(tab.isHidden()){
44544 this.tabs.unhideTab(tab.id);
44548 this.setActivePanel(panel);
44555 * Get the active panel for this region.
44556 * @return {Roo.ContentPanel} The active panel or null
44558 getActivePanel : function(){
44559 return this.activePanel;
44562 validateVisibility : function(){
44563 if(this.panels.getCount() < 1){
44564 this.updateTitle(" ");
44565 this.closeBtn.hide();
44568 if(!this.isVisible()){
44575 * Adds the passed ContentPanel(s) to this region.
44576 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44577 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44579 add : function(panel){
44580 if(arguments.length > 1){
44581 for(var i = 0, len = arguments.length; i < len; i++) {
44582 this.add(arguments[i]);
44586 if(this.hasPanel(panel)){
44587 this.showPanel(panel);
44590 panel.setRegion(this);
44591 this.panels.add(panel);
44592 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44593 this.bodyEl.dom.appendChild(panel.getEl().dom);
44594 if(panel.background !== true){
44595 this.setActivePanel(panel);
44597 this.fireEvent("paneladded", this, panel);
44603 this.initPanelAsTab(panel);
44605 if(panel.background !== true){
44606 this.tabs.activate(panel.getEl().id);
44608 this.fireEvent("paneladded", this, panel);
44613 * Hides the tab for the specified panel.
44614 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44616 hidePanel : function(panel){
44617 if(this.tabs && (panel = this.getPanel(panel))){
44618 this.tabs.hideTab(panel.getEl().id);
44623 * Unhides the tab for a previously hidden panel.
44624 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44626 unhidePanel : function(panel){
44627 if(this.tabs && (panel = this.getPanel(panel))){
44628 this.tabs.unhideTab(panel.getEl().id);
44632 clearPanels : function(){
44633 while(this.panels.getCount() > 0){
44634 this.remove(this.panels.first());
44639 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44640 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44641 * @param {Boolean} preservePanel Overrides the config preservePanel option
44642 * @return {Roo.ContentPanel} The panel that was removed
44644 remove : function(panel, preservePanel){
44645 panel = this.getPanel(panel);
44650 this.fireEvent("beforeremove", this, panel, e);
44651 if(e.cancel === true){
44654 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44655 var panelId = panel.getId();
44656 this.panels.removeKey(panelId);
44658 document.body.appendChild(panel.getEl().dom);
44661 this.tabs.removeTab(panel.getEl().id);
44662 }else if (!preservePanel){
44663 this.bodyEl.dom.removeChild(panel.getEl().dom);
44665 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44666 var p = this.panels.first();
44667 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44668 tempEl.appendChild(p.getEl().dom);
44669 this.bodyEl.update("");
44670 this.bodyEl.dom.appendChild(p.getEl().dom);
44672 this.updateTitle(p.getTitle());
44674 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44675 this.setActivePanel(p);
44677 panel.setRegion(null);
44678 if(this.activePanel == panel){
44679 this.activePanel = null;
44681 if(this.config.autoDestroy !== false && preservePanel !== true){
44682 try{panel.destroy();}catch(e){}
44684 this.fireEvent("panelremoved", this, panel);
44689 * Returns the TabPanel component used by this region
44690 * @return {Roo.TabPanel}
44692 getTabs : function(){
44696 createTool : function(parentEl, className){
44697 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44698 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44699 btn.addClassOnOver("x-layout-tools-button-over");
44704 * Ext JS Library 1.1.1
44705 * Copyright(c) 2006-2007, Ext JS, LLC.
44707 * Originally Released Under LGPL - original licence link has changed is not relivant.
44710 * <script type="text/javascript">
44716 * @class Roo.SplitLayoutRegion
44717 * @extends Roo.LayoutRegion
44718 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44720 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
44721 this.cursor = cursor;
44722 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
44725 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
44726 splitTip : "Drag to resize.",
44727 collapsibleSplitTip : "Drag to resize. Double click to hide.",
44728 useSplitTips : false,
44730 applyConfig : function(config){
44731 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
44734 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
44735 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
44736 /** The SplitBar for this region
44737 * @type Roo.SplitBar */
44738 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
44739 this.split.on("moved", this.onSplitMove, this);
44740 this.split.useShim = config.useShim === true;
44741 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
44742 if(this.useSplitTips){
44743 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
44745 if(config.collapsible){
44746 this.split.el.on("dblclick", this.collapse, this);
44749 if(typeof config.minSize != "undefined"){
44750 this.split.minSize = config.minSize;
44752 if(typeof config.maxSize != "undefined"){
44753 this.split.maxSize = config.maxSize;
44755 if(config.hideWhenEmpty || config.hidden || config.collapsed){
44756 this.hideSplitter();
44761 getHMaxSize : function(){
44762 var cmax = this.config.maxSize || 10000;
44763 var center = this.mgr.getRegion("center");
44764 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
44767 getVMaxSize : function(){
44768 var cmax = this.config.maxSize || 10000;
44769 var center = this.mgr.getRegion("center");
44770 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
44773 onSplitMove : function(split, newSize){
44774 this.fireEvent("resized", this, newSize);
44778 * Returns the {@link Roo.SplitBar} for this region.
44779 * @return {Roo.SplitBar}
44781 getSplitBar : function(){
44786 this.hideSplitter();
44787 Roo.SplitLayoutRegion.superclass.hide.call(this);
44790 hideSplitter : function(){
44792 this.split.el.setLocation(-2000,-2000);
44793 this.split.el.hide();
44799 this.split.el.show();
44801 Roo.SplitLayoutRegion.superclass.show.call(this);
44804 beforeSlide: function(){
44805 if(Roo.isGecko){// firefox overflow auto bug workaround
44806 this.bodyEl.clip();
44807 if(this.tabs) this.tabs.bodyEl.clip();
44808 if(this.activePanel){
44809 this.activePanel.getEl().clip();
44811 if(this.activePanel.beforeSlide){
44812 this.activePanel.beforeSlide();
44818 afterSlide : function(){
44819 if(Roo.isGecko){// firefox overflow auto bug workaround
44820 this.bodyEl.unclip();
44821 if(this.tabs) this.tabs.bodyEl.unclip();
44822 if(this.activePanel){
44823 this.activePanel.getEl().unclip();
44824 if(this.activePanel.afterSlide){
44825 this.activePanel.afterSlide();
44831 initAutoHide : function(){
44832 if(this.autoHide !== false){
44833 if(!this.autoHideHd){
44834 var st = new Roo.util.DelayedTask(this.slideIn, this);
44835 this.autoHideHd = {
44836 "mouseout": function(e){
44837 if(!e.within(this.el, true)){
44841 "mouseover" : function(e){
44847 this.el.on(this.autoHideHd);
44851 clearAutoHide : function(){
44852 if(this.autoHide !== false){
44853 this.el.un("mouseout", this.autoHideHd.mouseout);
44854 this.el.un("mouseover", this.autoHideHd.mouseover);
44858 clearMonitor : function(){
44859 Roo.get(document).un("click", this.slideInIf, this);
44862 // these names are backwards but not changed for compat
44863 slideOut : function(){
44864 if(this.isSlid || this.el.hasActiveFx()){
44867 this.isSlid = true;
44868 if(this.collapseBtn){
44869 this.collapseBtn.hide();
44871 this.closeBtnState = this.closeBtn.getStyle('display');
44872 this.closeBtn.hide();
44874 this.stickBtn.show();
44877 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
44878 this.beforeSlide();
44879 this.el.setStyle("z-index", 10001);
44880 this.el.slideIn(this.getSlideAnchor(), {
44881 callback: function(){
44883 this.initAutoHide();
44884 Roo.get(document).on("click", this.slideInIf, this);
44885 this.fireEvent("slideshow", this);
44892 afterSlideIn : function(){
44893 this.clearAutoHide();
44894 this.isSlid = false;
44895 this.clearMonitor();
44896 this.el.setStyle("z-index", "");
44897 if(this.collapseBtn){
44898 this.collapseBtn.show();
44900 this.closeBtn.setStyle('display', this.closeBtnState);
44902 this.stickBtn.hide();
44904 this.fireEvent("slidehide", this);
44907 slideIn : function(cb){
44908 if(!this.isSlid || this.el.hasActiveFx()){
44912 this.isSlid = false;
44913 this.beforeSlide();
44914 this.el.slideOut(this.getSlideAnchor(), {
44915 callback: function(){
44916 this.el.setLeftTop(-10000, -10000);
44918 this.afterSlideIn();
44926 slideInIf : function(e){
44927 if(!e.within(this.el)){
44932 animateCollapse : function(){
44933 this.beforeSlide();
44934 this.el.setStyle("z-index", 20000);
44935 var anchor = this.getSlideAnchor();
44936 this.el.slideOut(anchor, {
44937 callback : function(){
44938 this.el.setStyle("z-index", "");
44939 this.collapsedEl.slideIn(anchor, {duration:.3});
44941 this.el.setLocation(-10000,-10000);
44943 this.fireEvent("collapsed", this);
44950 animateExpand : function(){
44951 this.beforeSlide();
44952 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
44953 this.el.setStyle("z-index", 20000);
44954 this.collapsedEl.hide({
44957 this.el.slideIn(this.getSlideAnchor(), {
44958 callback : function(){
44959 this.el.setStyle("z-index", "");
44962 this.split.el.show();
44964 this.fireEvent("invalidated", this);
44965 this.fireEvent("expanded", this);
44993 getAnchor : function(){
44994 return this.anchors[this.position];
44997 getCollapseAnchor : function(){
44998 return this.canchors[this.position];
45001 getSlideAnchor : function(){
45002 return this.sanchors[this.position];
45005 getAlignAdj : function(){
45006 var cm = this.cmargins;
45007 switch(this.position){
45023 getExpandAdj : function(){
45024 var c = this.collapsedEl, cm = this.cmargins;
45025 switch(this.position){
45027 return [-(cm.right+c.getWidth()+cm.left), 0];
45030 return [cm.right+c.getWidth()+cm.left, 0];
45033 return [0, -(cm.top+cm.bottom+c.getHeight())];
45036 return [0, cm.top+cm.bottom+c.getHeight()];
45042 * Ext JS Library 1.1.1
45043 * Copyright(c) 2006-2007, Ext JS, LLC.
45045 * Originally Released Under LGPL - original licence link has changed is not relivant.
45048 * <script type="text/javascript">
45051 * These classes are private internal classes
45053 Roo.CenterLayoutRegion = function(mgr, config){
45054 Roo.LayoutRegion.call(this, mgr, config, "center");
45055 this.visible = true;
45056 this.minWidth = config.minWidth || 20;
45057 this.minHeight = config.minHeight || 20;
45060 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45062 // center panel can't be hidden
45066 // center panel can't be hidden
45069 getMinWidth: function(){
45070 return this.minWidth;
45073 getMinHeight: function(){
45074 return this.minHeight;
45079 Roo.NorthLayoutRegion = function(mgr, config){
45080 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45082 this.split.placement = Roo.SplitBar.TOP;
45083 this.split.orientation = Roo.SplitBar.VERTICAL;
45084 this.split.el.addClass("x-layout-split-v");
45086 var size = config.initialSize || config.height;
45087 if(typeof size != "undefined"){
45088 this.el.setHeight(size);
45091 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45092 orientation: Roo.SplitBar.VERTICAL,
45093 getBox : function(){
45094 if(this.collapsed){
45095 return this.collapsedEl.getBox();
45097 var box = this.el.getBox();
45099 box.height += this.split.el.getHeight();
45104 updateBox : function(box){
45105 if(this.split && !this.collapsed){
45106 box.height -= this.split.el.getHeight();
45107 this.split.el.setLeft(box.x);
45108 this.split.el.setTop(box.y+box.height);
45109 this.split.el.setWidth(box.width);
45111 if(this.collapsed){
45112 this.updateBody(box.width, null);
45114 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45118 Roo.SouthLayoutRegion = function(mgr, config){
45119 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45121 this.split.placement = Roo.SplitBar.BOTTOM;
45122 this.split.orientation = Roo.SplitBar.VERTICAL;
45123 this.split.el.addClass("x-layout-split-v");
45125 var size = config.initialSize || config.height;
45126 if(typeof size != "undefined"){
45127 this.el.setHeight(size);
45130 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45131 orientation: Roo.SplitBar.VERTICAL,
45132 getBox : function(){
45133 if(this.collapsed){
45134 return this.collapsedEl.getBox();
45136 var box = this.el.getBox();
45138 var sh = this.split.el.getHeight();
45145 updateBox : function(box){
45146 if(this.split && !this.collapsed){
45147 var sh = this.split.el.getHeight();
45150 this.split.el.setLeft(box.x);
45151 this.split.el.setTop(box.y-sh);
45152 this.split.el.setWidth(box.width);
45154 if(this.collapsed){
45155 this.updateBody(box.width, null);
45157 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45161 Roo.EastLayoutRegion = function(mgr, config){
45162 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45164 this.split.placement = Roo.SplitBar.RIGHT;
45165 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45166 this.split.el.addClass("x-layout-split-h");
45168 var size = config.initialSize || config.width;
45169 if(typeof size != "undefined"){
45170 this.el.setWidth(size);
45173 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45174 orientation: Roo.SplitBar.HORIZONTAL,
45175 getBox : function(){
45176 if(this.collapsed){
45177 return this.collapsedEl.getBox();
45179 var box = this.el.getBox();
45181 var sw = this.split.el.getWidth();
45188 updateBox : function(box){
45189 if(this.split && !this.collapsed){
45190 var sw = this.split.el.getWidth();
45192 this.split.el.setLeft(box.x);
45193 this.split.el.setTop(box.y);
45194 this.split.el.setHeight(box.height);
45197 if(this.collapsed){
45198 this.updateBody(null, box.height);
45200 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45204 Roo.WestLayoutRegion = function(mgr, config){
45205 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45207 this.split.placement = Roo.SplitBar.LEFT;
45208 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45209 this.split.el.addClass("x-layout-split-h");
45211 var size = config.initialSize || config.width;
45212 if(typeof size != "undefined"){
45213 this.el.setWidth(size);
45216 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45217 orientation: Roo.SplitBar.HORIZONTAL,
45218 getBox : function(){
45219 if(this.collapsed){
45220 return this.collapsedEl.getBox();
45222 var box = this.el.getBox();
45224 box.width += this.split.el.getWidth();
45229 updateBox : function(box){
45230 if(this.split && !this.collapsed){
45231 var sw = this.split.el.getWidth();
45233 this.split.el.setLeft(box.x+box.width);
45234 this.split.el.setTop(box.y);
45235 this.split.el.setHeight(box.height);
45237 if(this.collapsed){
45238 this.updateBody(null, box.height);
45240 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45245 * Ext JS Library 1.1.1
45246 * Copyright(c) 2006-2007, Ext JS, LLC.
45248 * Originally Released Under LGPL - original licence link has changed is not relivant.
45251 * <script type="text/javascript">
45256 * Private internal class for reading and applying state
45258 Roo.LayoutStateManager = function(layout){
45259 // default empty state
45268 Roo.LayoutStateManager.prototype = {
45269 init : function(layout, provider){
45270 this.provider = provider;
45271 var state = provider.get(layout.id+"-layout-state");
45273 var wasUpdating = layout.isUpdating();
45275 layout.beginUpdate();
45277 for(var key in state){
45278 if(typeof state[key] != "function"){
45279 var rstate = state[key];
45280 var r = layout.getRegion(key);
45283 r.resizeTo(rstate.size);
45285 if(rstate.collapsed == true){
45288 r.expand(null, true);
45294 layout.endUpdate();
45296 this.state = state;
45298 this.layout = layout;
45299 layout.on("regionresized", this.onRegionResized, this);
45300 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45301 layout.on("regionexpanded", this.onRegionExpanded, this);
45304 storeState : function(){
45305 this.provider.set(this.layout.id+"-layout-state", this.state);
45308 onRegionResized : function(region, newSize){
45309 this.state[region.getPosition()].size = newSize;
45313 onRegionCollapsed : function(region){
45314 this.state[region.getPosition()].collapsed = true;
45318 onRegionExpanded : function(region){
45319 this.state[region.getPosition()].collapsed = false;
45324 * Ext JS Library 1.1.1
45325 * Copyright(c) 2006-2007, Ext JS, LLC.
45327 * Originally Released Under LGPL - original licence link has changed is not relivant.
45330 * <script type="text/javascript">
45333 * @class Roo.ContentPanel
45334 * @extends Roo.util.Observable
45335 * A basic ContentPanel element.
45336 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45337 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45338 * @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
45339 * @cfg {Boolean} closable True if the panel can be closed/removed
45340 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45341 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45342 * @cfg {Toolbar} toolbar A toolbar for this panel
45343 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45344 * @cfg {String} title The title for this panel
45345 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45346 * @cfg {String} url Calls {@link #setUrl} with this value
45347 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45348 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45349 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45351 * Create a new ContentPanel.
45352 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45353 * @param {String/Object} config A string to set only the title or a config object
45354 * @param {String} content (optional) Set the HTML content for this panel
45355 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45357 Roo.ContentPanel = function(el, config, content){
45361 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45365 if (config && config.parentLayout) {
45366 el = config.parentLayout.el.createChild();
45369 if(el.autoCreate){ // xtype is available if this is called from factory
45373 this.el = Roo.get(el);
45374 if(!this.el && config && config.autoCreate){
45375 if(typeof config.autoCreate == "object"){
45376 if(!config.autoCreate.id){
45377 config.autoCreate.id = config.id||el;
45379 this.el = Roo.DomHelper.append(document.body,
45380 config.autoCreate, true);
45382 this.el = Roo.DomHelper.append(document.body,
45383 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45386 this.closable = false;
45387 this.loaded = false;
45388 this.active = false;
45389 if(typeof config == "string"){
45390 this.title = config;
45392 Roo.apply(this, config);
45395 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45396 this.wrapEl = this.el.wrap();
45397 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45404 this.resizeEl = Roo.get(this.resizeEl, true);
45406 this.resizeEl = this.el;
45411 * Fires when this panel is activated.
45412 * @param {Roo.ContentPanel} this
45416 * @event deactivate
45417 * Fires when this panel is activated.
45418 * @param {Roo.ContentPanel} this
45420 "deactivate" : true,
45424 * Fires when this panel is resized if fitToFrame is true.
45425 * @param {Roo.ContentPanel} this
45426 * @param {Number} width The width after any component adjustments
45427 * @param {Number} height The height after any component adjustments
45431 if(this.autoScroll){
45432 this.resizeEl.setStyle("overflow", "auto");
45434 // fix randome scrolling
45435 this.el.on('scroll', function() {
45436 this.scrollTo('top',0);
45439 content = content || this.content;
45441 this.setContent(content);
45443 if(config && config.url){
45444 this.setUrl(this.url, this.params, this.loadOnce);
45449 Roo.ContentPanel.superclass.constructor.call(this);
45452 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45454 setRegion : function(region){
45455 this.region = region;
45457 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45459 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45464 * Returns the toolbar for this Panel if one was configured.
45465 * @return {Roo.Toolbar}
45467 getToolbar : function(){
45468 return this.toolbar;
45471 setActiveState : function(active){
45472 this.active = active;
45474 this.fireEvent("deactivate", this);
45476 this.fireEvent("activate", this);
45480 * Updates this panel's element
45481 * @param {String} content The new content
45482 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45484 setContent : function(content, loadScripts){
45485 this.el.update(content, loadScripts);
45488 ignoreResize : function(w, h){
45489 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45492 this.lastSize = {width: w, height: h};
45497 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45498 * @return {Roo.UpdateManager} The UpdateManager
45500 getUpdateManager : function(){
45501 return this.el.getUpdateManager();
45504 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45505 * @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:
45508 url: "your-url.php",
45509 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45510 callback: yourFunction,
45511 scope: yourObject, //(optional scope)
45514 text: "Loading...",
45519 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45520 * 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.
45521 * @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}
45522 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45523 * @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.
45524 * @return {Roo.ContentPanel} this
45527 var um = this.el.getUpdateManager();
45528 um.update.apply(um, arguments);
45534 * 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.
45535 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45536 * @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)
45537 * @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)
45538 * @return {Roo.UpdateManager} The UpdateManager
45540 setUrl : function(url, params, loadOnce){
45541 if(this.refreshDelegate){
45542 this.removeListener("activate", this.refreshDelegate);
45544 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45545 this.on("activate", this.refreshDelegate);
45546 return this.el.getUpdateManager();
45549 _handleRefresh : function(url, params, loadOnce){
45550 if(!loadOnce || !this.loaded){
45551 var updater = this.el.getUpdateManager();
45552 updater.update(url, params, this._setLoaded.createDelegate(this));
45556 _setLoaded : function(){
45557 this.loaded = true;
45561 * Returns this panel's id
45564 getId : function(){
45569 * Returns this panel's element - used by regiosn to add.
45570 * @return {Roo.Element}
45572 getEl : function(){
45573 return this.wrapEl || this.el;
45576 adjustForComponents : function(width, height){
45577 if(this.resizeEl != this.el){
45578 width -= this.el.getFrameWidth('lr');
45579 height -= this.el.getFrameWidth('tb');
45582 var te = this.toolbar.getEl();
45583 height -= te.getHeight();
45584 te.setWidth(width);
45586 if(this.adjustments){
45587 width += this.adjustments[0];
45588 height += this.adjustments[1];
45590 return {"width": width, "height": height};
45593 setSize : function(width, height){
45594 if(this.fitToFrame && !this.ignoreResize(width, height)){
45595 if(this.fitContainer && this.resizeEl != this.el){
45596 this.el.setSize(width, height);
45598 var size = this.adjustForComponents(width, height);
45599 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45600 this.fireEvent('resize', this, size.width, size.height);
45605 * Returns this panel's title
45608 getTitle : function(){
45613 * Set this panel's title
45614 * @param {String} title
45616 setTitle : function(title){
45617 this.title = title;
45619 this.region.updatePanelTitle(this, title);
45624 * Returns true is this panel was configured to be closable
45625 * @return {Boolean}
45627 isClosable : function(){
45628 return this.closable;
45631 beforeSlide : function(){
45633 this.resizeEl.clip();
45636 afterSlide : function(){
45638 this.resizeEl.unclip();
45642 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45643 * Will fail silently if the {@link #setUrl} method has not been called.
45644 * This does not activate the panel, just updates its content.
45646 refresh : function(){
45647 if(this.refreshDelegate){
45648 this.loaded = false;
45649 this.refreshDelegate();
45654 * Destroys this panel
45656 destroy : function(){
45657 this.el.removeAllListeners();
45658 var tempEl = document.createElement("span");
45659 tempEl.appendChild(this.el.dom);
45660 tempEl.innerHTML = "";
45666 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45676 * @param {Object} cfg Xtype definition of item to add.
45679 addxtype : function(cfg) {
45681 if (cfg.xtype.match(/^Form$/)) {
45682 var el = this.el.createChild();
45684 this.form = new Roo.form.Form(cfg);
45687 if ( this.form.allItems.length) this.form.render(el.dom);
45690 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
45692 cfg.el = this.el.appendChild(document.createElement("div"));
45694 var ret = new Roo[cfg.xtype](cfg);
45695 ret.render(false, ''); // render blank..
45705 * @class Roo.GridPanel
45706 * @extends Roo.ContentPanel
45708 * Create a new GridPanel.
45709 * @param {Roo.grid.Grid} grid The grid for this panel
45710 * @param {String/Object} config A string to set only the panel's title, or a config object
45712 Roo.GridPanel = function(grid, config){
45715 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45716 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45718 this.wrapper.dom.appendChild(grid.getGridEl().dom);
45720 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
45723 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
45725 // xtype created footer. - not sure if will work as we normally have to render first..
45726 if (this.footer && !this.footer.el && this.footer.xtype) {
45728 this.footer.container = this.grid.getView().getFooterPanel(true);
45729 this.footer.dataSource = this.grid.dataSource;
45730 this.footer = Roo.factory(this.footer, Roo);
45734 grid.monitorWindowResize = false; // turn off autosizing
45735 grid.autoHeight = false;
45736 grid.autoWidth = false;
45738 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
45741 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
45742 getId : function(){
45743 return this.grid.id;
45747 * Returns the grid for this panel
45748 * @return {Roo.grid.Grid}
45750 getGrid : function(){
45754 setSize : function(width, height){
45755 if(!this.ignoreResize(width, height)){
45756 var grid = this.grid;
45757 var size = this.adjustForComponents(width, height);
45758 grid.getGridEl().setSize(size.width, size.height);
45763 beforeSlide : function(){
45764 this.grid.getView().scroller.clip();
45767 afterSlide : function(){
45768 this.grid.getView().scroller.unclip();
45771 destroy : function(){
45772 this.grid.destroy();
45774 Roo.GridPanel.superclass.destroy.call(this);
45780 * @class Roo.NestedLayoutPanel
45781 * @extends Roo.ContentPanel
45783 * Create a new NestedLayoutPanel.
45786 * @param {Roo.BorderLayout} layout The layout for this panel
45787 * @param {String/Object} config A string to set only the title or a config object
45789 Roo.NestedLayoutPanel = function(layout, config)
45791 // construct with only one argument..
45792 /* FIXME - implement nicer consturctors
45793 if (layout.layout) {
45795 layout = config.layout;
45796 delete config.layout;
45798 if (layout.xtype && !layout.getEl) {
45799 // then layout needs constructing..
45800 layout = Roo.factory(layout, Roo);
45805 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
45807 layout.monitorWindowResize = false; // turn off autosizing
45808 this.layout = layout;
45809 this.layout.getEl().addClass("x-layout-nested-layout");
45816 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
45818 setSize : function(width, height){
45819 if(!this.ignoreResize(width, height)){
45820 var size = this.adjustForComponents(width, height);
45821 var el = this.layout.getEl();
45822 el.setSize(size.width, size.height);
45823 var touch = el.dom.offsetWidth;
45824 this.layout.layout();
45825 // ie requires a double layout on the first pass
45826 if(Roo.isIE && !this.initialized){
45827 this.initialized = true;
45828 this.layout.layout();
45833 // activate all subpanels if not currently active..
45835 setActiveState : function(active){
45836 this.active = active;
45838 this.fireEvent("deactivate", this);
45842 this.fireEvent("activate", this);
45843 // not sure if this should happen before or after..
45844 if (!this.layout) {
45845 return; // should not happen..
45848 for (var r in this.layout.regions) {
45849 reg = this.layout.getRegion(r);
45850 if (reg.getActivePanel()) {
45851 //reg.showPanel(reg.getActivePanel()); // force it to activate..
45852 reg.setActivePanel(reg.getActivePanel());
45855 if (!reg.panels.length) {
45858 reg.showPanel(reg.getPanel(0));
45867 * Returns the nested BorderLayout for this panel
45868 * @return {Roo.BorderLayout}
45870 getLayout : function(){
45871 return this.layout;
45875 * Adds a xtype elements to the layout of the nested panel
45879 xtype : 'ContentPanel',
45886 xtype : 'NestedLayoutPanel',
45892 items : [ ... list of content panels or nested layout panels.. ]
45896 * @param {Object} cfg Xtype definition of item to add.
45898 addxtype : function(cfg) {
45899 return this.layout.addxtype(cfg);
45904 Roo.ScrollPanel = function(el, config, content){
45905 config = config || {};
45906 config.fitToFrame = true;
45907 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
45909 this.el.dom.style.overflow = "hidden";
45910 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
45911 this.el.removeClass("x-layout-inactive-content");
45912 this.el.on("mousewheel", this.onWheel, this);
45914 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
45915 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
45916 up.unselectable(); down.unselectable();
45917 up.on("click", this.scrollUp, this);
45918 down.on("click", this.scrollDown, this);
45919 up.addClassOnOver("x-scroller-btn-over");
45920 down.addClassOnOver("x-scroller-btn-over");
45921 up.addClassOnClick("x-scroller-btn-click");
45922 down.addClassOnClick("x-scroller-btn-click");
45923 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
45925 this.resizeEl = this.el;
45926 this.el = wrap; this.up = up; this.down = down;
45929 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
45931 wheelIncrement : 5,
45932 scrollUp : function(){
45933 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
45936 scrollDown : function(){
45937 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
45940 afterScroll : function(){
45941 var el = this.resizeEl;
45942 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
45943 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45944 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45947 setSize : function(){
45948 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
45949 this.afterScroll();
45952 onWheel : function(e){
45953 var d = e.getWheelDelta();
45954 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
45955 this.afterScroll();
45959 setContent : function(content, loadScripts){
45960 this.resizeEl.update(content, loadScripts);
45974 * @class Roo.TreePanel
45975 * @extends Roo.ContentPanel
45977 * Create a new TreePanel. - defaults to fit/scoll contents.
45978 * @param {String/Object} config A string to set only the panel's title, or a config object
45979 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
45981 Roo.TreePanel = function(config){
45982 var el = config.el;
45983 var tree = config.tree;
45984 delete config.tree;
45985 delete config.el; // hopefull!
45987 // wrapper for IE7 strict & safari scroll issue
45989 var treeEl = el.createChild();
45990 config.resizeEl = treeEl;
45994 Roo.TreePanel.superclass.constructor.call(this, el, config);
45997 this.tree = new Roo.tree.TreePanel(treeEl , tree);
45998 //console.log(tree);
45999 this.on('activate', function()
46001 if (this.tree.rendered) {
46004 //console.log('render tree');
46005 this.tree.render();
46008 this.on('resize', function (cp, w, h) {
46009 this.tree.innerCt.setWidth(w);
46010 this.tree.innerCt.setHeight(h);
46011 this.tree.innerCt.setStyle('overflow-y', 'auto');
46018 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
46035 * Ext JS Library 1.1.1
46036 * Copyright(c) 2006-2007, Ext JS, LLC.
46038 * Originally Released Under LGPL - original licence link has changed is not relivant.
46041 * <script type="text/javascript">
46046 * @class Roo.ReaderLayout
46047 * @extends Roo.BorderLayout
46048 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46049 * center region containing two nested regions (a top one for a list view and one for item preview below),
46050 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46051 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46052 * expedites the setup of the overall layout and regions for this common application style.
46055 var reader = new Roo.ReaderLayout();
46056 var CP = Roo.ContentPanel; // shortcut for adding
46058 reader.beginUpdate();
46059 reader.add("north", new CP("north", "North"));
46060 reader.add("west", new CP("west", {title: "West"}));
46061 reader.add("east", new CP("east", {title: "East"}));
46063 reader.regions.listView.add(new CP("listView", "List"));
46064 reader.regions.preview.add(new CP("preview", "Preview"));
46065 reader.endUpdate();
46068 * Create a new ReaderLayout
46069 * @param {Object} config Configuration options
46070 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46071 * document.body if omitted)
46073 Roo.ReaderLayout = function(config, renderTo){
46074 var c = config || {size:{}};
46075 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46076 north: c.north !== false ? Roo.apply({
46080 }, c.north) : false,
46081 west: c.west !== false ? Roo.apply({
46089 margins:{left:5,right:0,bottom:5,top:5},
46090 cmargins:{left:5,right:5,bottom:5,top:5}
46091 }, c.west) : false,
46092 east: c.east !== false ? Roo.apply({
46100 margins:{left:0,right:5,bottom:5,top:5},
46101 cmargins:{left:5,right:5,bottom:5,top:5}
46102 }, c.east) : false,
46103 center: Roo.apply({
46104 tabPosition: 'top',
46108 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46112 this.el.addClass('x-reader');
46114 this.beginUpdate();
46116 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46117 south: c.preview !== false ? Roo.apply({
46124 cmargins:{top:5,left:0, right:0, bottom:0}
46125 }, c.preview) : false,
46126 center: Roo.apply({
46132 this.add('center', new Roo.NestedLayoutPanel(inner,
46133 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46137 this.regions.preview = inner.getRegion('south');
46138 this.regions.listView = inner.getRegion('center');
46141 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46143 * Ext JS Library 1.1.1
46144 * Copyright(c) 2006-2007, Ext JS, LLC.
46146 * Originally Released Under LGPL - original licence link has changed is not relivant.
46149 * <script type="text/javascript">
46153 * @class Roo.grid.Grid
46154 * @extends Roo.util.Observable
46155 * This class represents the primary interface of a component based grid control.
46156 * <br><br>Usage:<pre><code>
46157 var grid = new Roo.grid.Grid("my-container-id", {
46160 selModel: mySelectionModel,
46161 autoSizeColumns: true,
46162 monitorWindowResize: false,
46163 trackMouseOver: true
46168 * <b>Common Problems:</b><br/>
46169 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46170 * element will correct this<br/>
46171 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46172 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46173 * are unpredictable.<br/>
46174 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46175 * grid to calculate dimensions/offsets.<br/>
46177 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46178 * The container MUST have some type of size defined for the grid to fill. The container will be
46179 * automatically set to position relative if it isn't already.
46180 * @param {Object} config A config object that sets properties on this grid.
46182 Roo.grid.Grid = function(container, config){
46183 // initialize the container
46184 this.container = Roo.get(container);
46185 this.container.update("");
46186 this.container.setStyle("overflow", "hidden");
46187 this.container.addClass('x-grid-container');
46189 this.id = this.container.id;
46191 Roo.apply(this, config);
46192 // check and correct shorthanded configs
46194 this.dataSource = this.ds;
46198 this.colModel = this.cm;
46202 this.selModel = this.sm;
46206 if (this.selModel) {
46207 this.selModel = Roo.factory(this.selModel, Roo.grid);
46208 this.sm = this.selModel;
46209 this.sm.xmodule = this.xmodule || false;
46211 if (typeof(this.colModel.config) == 'undefined') {
46212 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46213 this.cm = this.colModel;
46214 this.cm.xmodule = this.xmodule || false;
46216 if (this.dataSource) {
46217 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46218 this.ds = this.dataSource;
46219 this.ds.xmodule = this.xmodule || false;
46226 this.container.setWidth(this.width);
46230 this.container.setHeight(this.height);
46237 * The raw click event for the entire grid.
46238 * @param {Roo.EventObject} e
46243 * The raw dblclick event for the entire grid.
46244 * @param {Roo.EventObject} e
46248 * @event contextmenu
46249 * The raw contextmenu event for the entire grid.
46250 * @param {Roo.EventObject} e
46252 "contextmenu" : true,
46255 * The raw mousedown event for the entire grid.
46256 * @param {Roo.EventObject} e
46258 "mousedown" : true,
46261 * The raw mouseup event for the entire grid.
46262 * @param {Roo.EventObject} e
46267 * The raw mouseover event for the entire grid.
46268 * @param {Roo.EventObject} e
46270 "mouseover" : true,
46273 * The raw mouseout event for the entire grid.
46274 * @param {Roo.EventObject} e
46279 * The raw keypress event for the entire grid.
46280 * @param {Roo.EventObject} e
46285 * The raw keydown event for the entire grid.
46286 * @param {Roo.EventObject} e
46294 * Fires when a cell is clicked
46295 * @param {Grid} this
46296 * @param {Number} rowIndex
46297 * @param {Number} columnIndex
46298 * @param {Roo.EventObject} e
46300 "cellclick" : true,
46302 * @event celldblclick
46303 * Fires when a cell is double clicked
46304 * @param {Grid} this
46305 * @param {Number} rowIndex
46306 * @param {Number} columnIndex
46307 * @param {Roo.EventObject} e
46309 "celldblclick" : true,
46312 * Fires when a row is clicked
46313 * @param {Grid} this
46314 * @param {Number} rowIndex
46315 * @param {Roo.EventObject} e
46319 * @event rowdblclick
46320 * Fires when a row is double clicked
46321 * @param {Grid} this
46322 * @param {Number} rowIndex
46323 * @param {Roo.EventObject} e
46325 "rowdblclick" : true,
46327 * @event headerclick
46328 * Fires when a header is clicked
46329 * @param {Grid} this
46330 * @param {Number} columnIndex
46331 * @param {Roo.EventObject} e
46333 "headerclick" : true,
46335 * @event headerdblclick
46336 * Fires when a header cell is double clicked
46337 * @param {Grid} this
46338 * @param {Number} columnIndex
46339 * @param {Roo.EventObject} e
46341 "headerdblclick" : true,
46343 * @event rowcontextmenu
46344 * Fires when a row is right clicked
46345 * @param {Grid} this
46346 * @param {Number} rowIndex
46347 * @param {Roo.EventObject} e
46349 "rowcontextmenu" : true,
46351 * @event cellcontextmenu
46352 * Fires when a cell is right clicked
46353 * @param {Grid} this
46354 * @param {Number} rowIndex
46355 * @param {Number} cellIndex
46356 * @param {Roo.EventObject} e
46358 "cellcontextmenu" : true,
46360 * @event headercontextmenu
46361 * Fires when a header is right clicked
46362 * @param {Grid} this
46363 * @param {Number} columnIndex
46364 * @param {Roo.EventObject} e
46366 "headercontextmenu" : true,
46368 * @event bodyscroll
46369 * Fires when the body element is scrolled
46370 * @param {Number} scrollLeft
46371 * @param {Number} scrollTop
46373 "bodyscroll" : true,
46375 * @event columnresize
46376 * Fires when the user resizes a column
46377 * @param {Number} columnIndex
46378 * @param {Number} newSize
46380 "columnresize" : true,
46382 * @event columnmove
46383 * Fires when the user moves a column
46384 * @param {Number} oldIndex
46385 * @param {Number} newIndex
46387 "columnmove" : true,
46390 * Fires when row(s) start being dragged
46391 * @param {Grid} this
46392 * @param {Roo.GridDD} dd The drag drop object
46393 * @param {event} e The raw browser event
46395 "startdrag" : true,
46398 * Fires when a drag operation is complete
46399 * @param {Grid} this
46400 * @param {Roo.GridDD} dd The drag drop object
46401 * @param {event} e The raw browser event
46406 * Fires when dragged row(s) are dropped on a valid DD target
46407 * @param {Grid} this
46408 * @param {Roo.GridDD} dd The drag drop object
46409 * @param {String} targetId The target drag drop object
46410 * @param {event} e The raw browser event
46415 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46416 * @param {Grid} this
46417 * @param {Roo.GridDD} dd The drag drop object
46418 * @param {String} targetId The target drag drop object
46419 * @param {event} e The raw browser event
46424 * Fires when the dragged row(s) first cross another DD target while being dragged
46425 * @param {Grid} this
46426 * @param {Roo.GridDD} dd The drag drop object
46427 * @param {String} targetId The target drag drop object
46428 * @param {event} e The raw browser event
46430 "dragenter" : true,
46433 * Fires when the dragged row(s) leave another DD target while being dragged
46434 * @param {Grid} this
46435 * @param {Roo.GridDD} dd The drag drop object
46436 * @param {String} targetId The target drag drop object
46437 * @param {event} e The raw browser event
46442 * Fires when a row is rendered, so you can change add a style to it.
46443 * @param {GridView} gridview The grid view
46444 * @param {Object} rowcfg contains record, rowIndex and rowClass - set rowClass to add a style.
46450 * Fires when the grid is rendered
46451 * @param {Grid} grid
46456 Roo.grid.Grid.superclass.constructor.call(this);
46458 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46461 * @cfg {String} ddGroup - drag drop group.
46465 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46467 minColumnWidth : 25,
46470 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46471 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46472 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46474 autoSizeColumns : false,
46477 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46479 autoSizeHeaders : true,
46482 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46484 monitorWindowResize : true,
46487 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46488 * rows measured to get a columns size. Default is 0 (all rows).
46490 maxRowsToMeasure : 0,
46493 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46495 trackMouseOver : true,
46498 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46502 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46504 enableDragDrop : false,
46507 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46509 enableColumnMove : true,
46512 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46514 enableColumnHide : true,
46517 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46519 enableRowHeightSync : false,
46522 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46527 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46529 autoHeight : false,
46532 * @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.
46534 autoExpandColumn : false,
46537 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46540 autoExpandMin : 50,
46543 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46545 autoExpandMax : 1000,
46548 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46553 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46557 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46564 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46565 * of a fixed width. Default is false.
46568 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46571 * Called once after all setup has been completed and the grid is ready to be rendered.
46572 * @return {Roo.grid.Grid} this
46574 render : function(){
46575 var c = this.container;
46576 // try to detect autoHeight/width mode
46577 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46578 this.autoHeight = true;
46580 var view = this.getView();
46583 c.on("click", this.onClick, this);
46584 c.on("dblclick", this.onDblClick, this);
46585 c.on("contextmenu", this.onContextMenu, this);
46586 c.on("keydown", this.onKeyDown, this);
46588 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46590 this.getSelectionModel().init(this);
46595 this.loadMask = new Roo.LoadMask(this.container,
46596 Roo.apply({store:this.dataSource}, this.loadMask));
46600 if (this.toolbar && this.toolbar.xtype) {
46601 this.toolbar.container = this.getView().getHeaderPanel(true);
46602 this.toolbar = new Ext.Toolbar(this.toolbar);
46604 if (this.footer && this.footer.xtype) {
46605 this.footer.dataSource = this.getDataSource();
46606 this.footer.container = this.getView().getFooterPanel(true);
46607 this.footer = Roo.factory(this.footer, Roo);
46609 if (this.dropTarget && this.dropTarget.xtype) {
46610 delete this.dropTarget.xtype;
46611 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46615 this.rendered = true;
46616 this.fireEvent('render', this);
46621 * Reconfigures the grid to use a different Store and Column Model.
46622 * The View will be bound to the new objects and refreshed.
46623 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46624 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46626 reconfigure : function(dataSource, colModel){
46628 this.loadMask.destroy();
46629 this.loadMask = new Roo.LoadMask(this.container,
46630 Roo.apply({store:dataSource}, this.loadMask));
46632 this.view.bind(dataSource, colModel);
46633 this.dataSource = dataSource;
46634 this.colModel = colModel;
46635 this.view.refresh(true);
46639 onKeyDown : function(e){
46640 this.fireEvent("keydown", e);
46644 * Destroy this grid.
46645 * @param {Boolean} removeEl True to remove the element
46647 destroy : function(removeEl, keepListeners){
46649 this.loadMask.destroy();
46651 var c = this.container;
46652 c.removeAllListeners();
46653 this.view.destroy();
46654 this.colModel.purgeListeners();
46655 if(!keepListeners){
46656 this.purgeListeners();
46659 if(removeEl === true){
46665 processEvent : function(name, e){
46666 this.fireEvent(name, e);
46667 var t = e.getTarget();
46669 var header = v.findHeaderIndex(t);
46670 if(header !== false){
46671 this.fireEvent("header" + name, this, header, e);
46673 var row = v.findRowIndex(t);
46674 var cell = v.findCellIndex(t);
46676 this.fireEvent("row" + name, this, row, e);
46677 if(cell !== false){
46678 this.fireEvent("cell" + name, this, row, cell, e);
46685 onClick : function(e){
46686 this.processEvent("click", e);
46690 onContextMenu : function(e, t){
46691 this.processEvent("contextmenu", e);
46695 onDblClick : function(e){
46696 this.processEvent("dblclick", e);
46700 walkCells : function(row, col, step, fn, scope){
46701 var cm = this.colModel, clen = cm.getColumnCount();
46702 var ds = this.dataSource, rlen = ds.getCount(), first = true;
46714 if(fn.call(scope || this, row, col, cm) === true){
46732 if(fn.call(scope || this, row, col, cm) === true){
46744 getSelections : function(){
46745 return this.selModel.getSelections();
46749 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
46750 * but if manual update is required this method will initiate it.
46752 autoSize : function(){
46754 this.view.layout();
46755 if(this.view.adjustForScroll){
46756 this.view.adjustForScroll();
46762 * Returns the grid's underlying element.
46763 * @return {Element} The element
46765 getGridEl : function(){
46766 return this.container;
46769 // private for compatibility, overridden by editor grid
46770 stopEditing : function(){},
46773 * Returns the grid's SelectionModel.
46774 * @return {SelectionModel}
46776 getSelectionModel : function(){
46777 if(!this.selModel){
46778 this.selModel = new Roo.grid.RowSelectionModel();
46780 return this.selModel;
46784 * Returns the grid's DataSource.
46785 * @return {DataSource}
46787 getDataSource : function(){
46788 return this.dataSource;
46792 * Returns the grid's ColumnModel.
46793 * @return {ColumnModel}
46795 getColumnModel : function(){
46796 return this.colModel;
46800 * Returns the grid's GridView object.
46801 * @return {GridView}
46803 getView : function(){
46805 this.view = new Roo.grid.GridView(this.viewConfig);
46810 * Called to get grid's drag proxy text, by default returns this.ddText.
46813 getDragDropText : function(){
46814 var count = this.selModel.getCount();
46815 return String.format(this.ddText, count, count == 1 ? '' : 's');
46819 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
46820 * %0 is replaced with the number of selected rows.
46823 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
46825 * Ext JS Library 1.1.1
46826 * Copyright(c) 2006-2007, Ext JS, LLC.
46828 * Originally Released Under LGPL - original licence link has changed is not relivant.
46831 * <script type="text/javascript">
46834 Roo.grid.AbstractGridView = function(){
46838 "beforerowremoved" : true,
46839 "beforerowsinserted" : true,
46840 "beforerefresh" : true,
46841 "rowremoved" : true,
46842 "rowsinserted" : true,
46843 "rowupdated" : true,
46846 Roo.grid.AbstractGridView.superclass.constructor.call(this);
46849 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
46850 rowClass : "x-grid-row",
46851 cellClass : "x-grid-cell",
46852 tdClass : "x-grid-td",
46853 hdClass : "x-grid-hd",
46854 splitClass : "x-grid-hd-split",
46856 init: function(grid){
46858 var cid = this.grid.getGridEl().id;
46859 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
46860 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
46861 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
46862 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
46865 getColumnRenderers : function(){
46866 var renderers = [];
46867 var cm = this.grid.colModel;
46868 var colCount = cm.getColumnCount();
46869 for(var i = 0; i < colCount; i++){
46870 renderers[i] = cm.getRenderer(i);
46875 getColumnIds : function(){
46877 var cm = this.grid.colModel;
46878 var colCount = cm.getColumnCount();
46879 for(var i = 0; i < colCount; i++){
46880 ids[i] = cm.getColumnId(i);
46885 getDataIndexes : function(){
46886 if(!this.indexMap){
46887 this.indexMap = this.buildIndexMap();
46889 return this.indexMap.colToData;
46892 getColumnIndexByDataIndex : function(dataIndex){
46893 if(!this.indexMap){
46894 this.indexMap = this.buildIndexMap();
46896 return this.indexMap.dataToCol[dataIndex];
46900 * Set a css style for a column dynamically.
46901 * @param {Number} colIndex The index of the column
46902 * @param {String} name The css property name
46903 * @param {String} value The css value
46905 setCSSStyle : function(colIndex, name, value){
46906 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
46907 Roo.util.CSS.updateRule(selector, name, value);
46910 generateRules : function(cm){
46911 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
46912 Roo.util.CSS.removeStyleSheet(rulesId);
46913 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46914 var cid = cm.getColumnId(i);
46915 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
46916 this.tdSelector, cid, " {\n}\n",
46917 this.hdSelector, cid, " {\n}\n",
46918 this.splitSelector, cid, " {\n}\n");
46920 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46924 * Ext JS Library 1.1.1
46925 * Copyright(c) 2006-2007, Ext JS, LLC.
46927 * Originally Released Under LGPL - original licence link has changed is not relivant.
46930 * <script type="text/javascript">
46934 // This is a support class used internally by the Grid components
46935 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
46937 this.view = grid.getView();
46938 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46939 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
46941 this.setHandleElId(Roo.id(hd));
46942 this.setOuterHandleElId(Roo.id(hd2));
46944 this.scroll = false;
46946 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
46948 getDragData : function(e){
46949 var t = Roo.lib.Event.getTarget(e);
46950 var h = this.view.findHeaderCell(t);
46952 return {ddel: h.firstChild, header:h};
46957 onInitDrag : function(e){
46958 this.view.headersDisabled = true;
46959 var clone = this.dragData.ddel.cloneNode(true);
46960 clone.id = Roo.id();
46961 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
46962 this.proxy.update(clone);
46966 afterValidDrop : function(){
46968 setTimeout(function(){
46969 v.headersDisabled = false;
46973 afterInvalidDrop : function(){
46975 setTimeout(function(){
46976 v.headersDisabled = false;
46982 * Ext JS Library 1.1.1
46983 * Copyright(c) 2006-2007, Ext JS, LLC.
46985 * Originally Released Under LGPL - original licence link has changed is not relivant.
46988 * <script type="text/javascript">
46991 // This is a support class used internally by the Grid components
46992 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
46994 this.view = grid.getView();
46995 // split the proxies so they don't interfere with mouse events
46996 this.proxyTop = Roo.DomHelper.append(document.body, {
46997 cls:"col-move-top", html:" "
46999 this.proxyBottom = Roo.DomHelper.append(document.body, {
47000 cls:"col-move-bottom", html:" "
47002 this.proxyTop.hide = this.proxyBottom.hide = function(){
47003 this.setLeftTop(-100,-100);
47004 this.setStyle("visibility", "hidden");
47006 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47007 // temporarily disabled
47008 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
47009 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
47011 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
47012 proxyOffsets : [-4, -9],
47013 fly: Roo.Element.fly,
47015 getTargetFromEvent : function(e){
47016 var t = Roo.lib.Event.getTarget(e);
47017 var cindex = this.view.findCellIndex(t);
47018 if(cindex !== false){
47019 return this.view.getHeaderCell(cindex);
47023 nextVisible : function(h){
47024 var v = this.view, cm = this.grid.colModel;
47027 if(!cm.isHidden(v.getCellIndex(h))){
47035 prevVisible : function(h){
47036 var v = this.view, cm = this.grid.colModel;
47039 if(!cm.isHidden(v.getCellIndex(h))){
47047 positionIndicator : function(h, n, e){
47048 var x = Roo.lib.Event.getPageX(e);
47049 var r = Roo.lib.Dom.getRegion(n.firstChild);
47050 var px, pt, py = r.top + this.proxyOffsets[1];
47051 if((r.right - x) <= (r.right-r.left)/2){
47052 px = r.right+this.view.borderWidth;
47058 var oldIndex = this.view.getCellIndex(h);
47059 var newIndex = this.view.getCellIndex(n);
47061 if(this.grid.colModel.isFixed(newIndex)){
47065 var locked = this.grid.colModel.isLocked(newIndex);
47070 if(oldIndex < newIndex){
47073 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47076 px += this.proxyOffsets[0];
47077 this.proxyTop.setLeftTop(px, py);
47078 this.proxyTop.show();
47079 if(!this.bottomOffset){
47080 this.bottomOffset = this.view.mainHd.getHeight();
47082 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47083 this.proxyBottom.show();
47087 onNodeEnter : function(n, dd, e, data){
47088 if(data.header != n){
47089 this.positionIndicator(data.header, n, e);
47093 onNodeOver : function(n, dd, e, data){
47094 var result = false;
47095 if(data.header != n){
47096 result = this.positionIndicator(data.header, n, e);
47099 this.proxyTop.hide();
47100 this.proxyBottom.hide();
47102 return result ? this.dropAllowed : this.dropNotAllowed;
47105 onNodeOut : function(n, dd, e, data){
47106 this.proxyTop.hide();
47107 this.proxyBottom.hide();
47110 onNodeDrop : function(n, dd, e, data){
47111 var h = data.header;
47113 var cm = this.grid.colModel;
47114 var x = Roo.lib.Event.getPageX(e);
47115 var r = Roo.lib.Dom.getRegion(n.firstChild);
47116 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47117 var oldIndex = this.view.getCellIndex(h);
47118 var newIndex = this.view.getCellIndex(n);
47119 var locked = cm.isLocked(newIndex);
47123 if(oldIndex < newIndex){
47126 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47129 cm.setLocked(oldIndex, locked, true);
47130 cm.moveColumn(oldIndex, newIndex);
47131 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47139 * Ext JS Library 1.1.1
47140 * Copyright(c) 2006-2007, Ext JS, LLC.
47142 * Originally Released Under LGPL - original licence link has changed is not relivant.
47145 * <script type="text/javascript">
47149 * @class Roo.grid.GridView
47150 * @extends Roo.util.Observable
47153 * @param {Object} config
47155 Roo.grid.GridView = function(config){
47156 Roo.grid.GridView.superclass.constructor.call(this);
47159 Roo.apply(this, config);
47162 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47165 * Override this function to apply custom css classes to rows during rendering
47166 * @param {Record} record The record
47167 * @param {Number} index
47168 * @method getRowClass
47170 rowClass : "x-grid-row",
47172 cellClass : "x-grid-col",
47174 tdClass : "x-grid-td",
47176 hdClass : "x-grid-hd",
47178 splitClass : "x-grid-split",
47180 sortClasses : ["sort-asc", "sort-desc"],
47182 enableMoveAnim : false,
47186 dh : Roo.DomHelper,
47188 fly : Roo.Element.fly,
47190 css : Roo.util.CSS,
47196 scrollIncrement : 22,
47198 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47200 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47202 bind : function(ds, cm){
47204 this.ds.un("load", this.onLoad, this);
47205 this.ds.un("datachanged", this.onDataChange, this);
47206 this.ds.un("add", this.onAdd, this);
47207 this.ds.un("remove", this.onRemove, this);
47208 this.ds.un("update", this.onUpdate, this);
47209 this.ds.un("clear", this.onClear, this);
47212 ds.on("load", this.onLoad, this);
47213 ds.on("datachanged", this.onDataChange, this);
47214 ds.on("add", this.onAdd, this);
47215 ds.on("remove", this.onRemove, this);
47216 ds.on("update", this.onUpdate, this);
47217 ds.on("clear", this.onClear, this);
47222 this.cm.un("widthchange", this.onColWidthChange, this);
47223 this.cm.un("headerchange", this.onHeaderChange, this);
47224 this.cm.un("hiddenchange", this.onHiddenChange, this);
47225 this.cm.un("columnmoved", this.onColumnMove, this);
47226 this.cm.un("columnlockchange", this.onColumnLock, this);
47229 this.generateRules(cm);
47230 cm.on("widthchange", this.onColWidthChange, this);
47231 cm.on("headerchange", this.onHeaderChange, this);
47232 cm.on("hiddenchange", this.onHiddenChange, this);
47233 cm.on("columnmoved", this.onColumnMove, this);
47234 cm.on("columnlockchange", this.onColumnLock, this);
47239 init: function(grid){
47240 Roo.grid.GridView.superclass.init.call(this, grid);
47242 this.bind(grid.dataSource, grid.colModel);
47244 grid.on("headerclick", this.handleHeaderClick, this);
47246 if(grid.trackMouseOver){
47247 grid.on("mouseover", this.onRowOver, this);
47248 grid.on("mouseout", this.onRowOut, this);
47250 grid.cancelTextSelection = function(){};
47251 this.gridId = grid.id;
47253 var tpls = this.templates || {};
47256 tpls.master = new Roo.Template(
47257 '<div class="x-grid" hidefocus="true">',
47258 '<div class="x-grid-topbar"></div>',
47259 '<div class="x-grid-scroller"><div></div></div>',
47260 '<div class="x-grid-locked">',
47261 '<div class="x-grid-header">{lockedHeader}</div>',
47262 '<div class="x-grid-body">{lockedBody}</div>',
47264 '<div class="x-grid-viewport">',
47265 '<div class="x-grid-header">{header}</div>',
47266 '<div class="x-grid-body">{body}</div>',
47268 '<div class="x-grid-bottombar"></div>',
47269 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47270 '<div class="x-grid-resize-proxy"> </div>',
47273 tpls.master.disableformats = true;
47277 tpls.header = new Roo.Template(
47278 '<table border="0" cellspacing="0" cellpadding="0">',
47279 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47282 tpls.header.disableformats = true;
47284 tpls.header.compile();
47287 tpls.hcell = new Roo.Template(
47288 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47289 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47292 tpls.hcell.disableFormats = true;
47294 tpls.hcell.compile();
47297 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47298 tpls.hsplit.disableFormats = true;
47300 tpls.hsplit.compile();
47303 tpls.body = new Roo.Template(
47304 '<table border="0" cellspacing="0" cellpadding="0">',
47305 "<tbody>{rows}</tbody>",
47308 tpls.body.disableFormats = true;
47310 tpls.body.compile();
47313 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47314 tpls.row.disableFormats = true;
47316 tpls.row.compile();
47319 tpls.cell = new Roo.Template(
47320 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47321 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47324 tpls.cell.disableFormats = true;
47326 tpls.cell.compile();
47328 this.templates = tpls;
47331 // remap these for backwards compat
47332 onColWidthChange : function(){
47333 this.updateColumns.apply(this, arguments);
47335 onHeaderChange : function(){
47336 this.updateHeaders.apply(this, arguments);
47338 onHiddenChange : function(){
47339 this.handleHiddenChange.apply(this, arguments);
47341 onColumnMove : function(){
47342 this.handleColumnMove.apply(this, arguments);
47344 onColumnLock : function(){
47345 this.handleLockChange.apply(this, arguments);
47348 onDataChange : function(){
47350 this.updateHeaderSortState();
47353 onClear : function(){
47357 onUpdate : function(ds, record){
47358 this.refreshRow(record);
47361 refreshRow : function(record){
47362 var ds = this.ds, index;
47363 if(typeof record == 'number'){
47365 record = ds.getAt(index);
47367 index = ds.indexOf(record);
47369 this.insertRows(ds, index, index, true);
47370 this.onRemove(ds, record, index+1, true);
47371 this.syncRowHeights(index, index);
47373 this.fireEvent("rowupdated", this, index, record);
47376 onAdd : function(ds, records, index){
47377 this.insertRows(ds, index, index + (records.length-1));
47380 onRemove : function(ds, record, index, isUpdate){
47381 if(isUpdate !== true){
47382 this.fireEvent("beforerowremoved", this, index, record);
47384 var bt = this.getBodyTable(), lt = this.getLockedTable();
47385 if(bt.rows[index]){
47386 bt.firstChild.removeChild(bt.rows[index]);
47388 if(lt.rows[index]){
47389 lt.firstChild.removeChild(lt.rows[index]);
47391 if(isUpdate !== true){
47392 this.stripeRows(index);
47393 this.syncRowHeights(index, index);
47395 this.fireEvent("rowremoved", this, index, record);
47399 onLoad : function(){
47400 this.scrollToTop();
47404 * Scrolls the grid to the top
47406 scrollToTop : function(){
47408 this.scroller.dom.scrollTop = 0;
47414 * Gets a panel in the header of the grid that can be used for toolbars etc.
47415 * After modifying the contents of this panel a call to grid.autoSize() may be
47416 * required to register any changes in size.
47417 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47418 * @return Roo.Element
47420 getHeaderPanel : function(doShow){
47422 this.headerPanel.show();
47424 return this.headerPanel;
47428 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47429 * After modifying the contents of this panel a call to grid.autoSize() may be
47430 * required to register any changes in size.
47431 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47432 * @return Roo.Element
47434 getFooterPanel : function(doShow){
47436 this.footerPanel.show();
47438 return this.footerPanel;
47441 initElements : function(){
47442 var E = Roo.Element;
47443 var el = this.grid.getGridEl().dom.firstChild;
47444 var cs = el.childNodes;
47446 this.el = new E(el);
47447 this.headerPanel = new E(el.firstChild);
47448 this.headerPanel.enableDisplayMode("block");
47450 this.scroller = new E(cs[1]);
47451 this.scrollSizer = new E(this.scroller.dom.firstChild);
47453 this.lockedWrap = new E(cs[2]);
47454 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47455 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47457 this.mainWrap = new E(cs[3]);
47458 this.mainHd = new E(this.mainWrap.dom.firstChild);
47459 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47461 this.footerPanel = new E(cs[4]);
47462 this.footerPanel.enableDisplayMode("block");
47464 this.focusEl = new E(cs[5]);
47465 this.focusEl.swallowEvent("click", true);
47466 this.resizeProxy = new E(cs[6]);
47468 this.headerSelector = String.format(
47469 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47470 this.lockedHd.id, this.mainHd.id
47473 this.splitterSelector = String.format(
47474 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47475 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47478 idToCssName : function(s)
47480 return s.replace(/[^a-z0-9]+/ig, '-');
47483 getHeaderCell : function(index){
47484 return Roo.DomQuery.select(this.headerSelector)[index];
47487 getHeaderCellMeasure : function(index){
47488 return this.getHeaderCell(index).firstChild;
47491 getHeaderCellText : function(index){
47492 return this.getHeaderCell(index).firstChild.firstChild;
47495 getLockedTable : function(){
47496 return this.lockedBody.dom.firstChild;
47499 getBodyTable : function(){
47500 return this.mainBody.dom.firstChild;
47503 getLockedRow : function(index){
47504 return this.getLockedTable().rows[index];
47507 getRow : function(index){
47508 return this.getBodyTable().rows[index];
47511 getRowComposite : function(index){
47513 this.rowEl = new Roo.CompositeElementLite();
47515 var els = [], lrow, mrow;
47516 if(lrow = this.getLockedRow(index)){
47519 if(mrow = this.getRow(index)){
47522 this.rowEl.elements = els;
47526 getCell : function(rowIndex, colIndex){
47527 var locked = this.cm.getLockedCount();
47529 if(colIndex < locked){
47530 source = this.lockedBody.dom.firstChild;
47532 source = this.mainBody.dom.firstChild;
47533 colIndex -= locked;
47535 return source.rows[rowIndex].childNodes[colIndex];
47538 getCellText : function(rowIndex, colIndex){
47539 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47542 getCellBox : function(cell){
47543 var b = this.fly(cell).getBox();
47544 if(Roo.isOpera){ // opera fails to report the Y
47545 b.y = cell.offsetTop + this.mainBody.getY();
47550 getCellIndex : function(cell){
47551 var id = String(cell.className).match(this.cellRE);
47553 return parseInt(id[1], 10);
47558 findHeaderIndex : function(n){
47559 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47560 return r ? this.getCellIndex(r) : false;
47563 findHeaderCell : function(n){
47564 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47565 return r ? r : false;
47568 findRowIndex : function(n){
47572 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47573 return r ? r.rowIndex : false;
47576 findCellIndex : function(node){
47577 var stop = this.el.dom;
47578 while(node && node != stop){
47579 if(this.findRE.test(node.className)){
47580 return this.getCellIndex(node);
47582 node = node.parentNode;
47587 getColumnId : function(index){
47588 return this.cm.getColumnId(index);
47591 getSplitters : function(){
47592 if(this.splitterSelector){
47593 return Roo.DomQuery.select(this.splitterSelector);
47599 getSplitter : function(index){
47600 return this.getSplitters()[index];
47603 onRowOver : function(e, t){
47605 if((row = this.findRowIndex(t)) !== false){
47606 this.getRowComposite(row).addClass("x-grid-row-over");
47610 onRowOut : function(e, t){
47612 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47613 this.getRowComposite(row).removeClass("x-grid-row-over");
47617 renderHeaders : function(){
47619 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47620 var cb = [], lb = [], sb = [], lsb = [], p = {};
47621 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47622 p.cellId = "x-grid-hd-0-" + i;
47623 p.splitId = "x-grid-csplit-0-" + i;
47624 p.id = cm.getColumnId(i);
47625 p.title = cm.getColumnTooltip(i) || "";
47626 p.value = cm.getColumnHeader(i) || "";
47627 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47628 if(!cm.isLocked(i)){
47629 cb[cb.length] = ct.apply(p);
47630 sb[sb.length] = st.apply(p);
47632 lb[lb.length] = ct.apply(p);
47633 lsb[lsb.length] = st.apply(p);
47636 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47637 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47640 updateHeaders : function(){
47641 var html = this.renderHeaders();
47642 this.lockedHd.update(html[0]);
47643 this.mainHd.update(html[1]);
47647 * Focuses the specified row.
47648 * @param {Number} row The row index
47650 focusRow : function(row){
47651 var x = this.scroller.dom.scrollLeft;
47652 this.focusCell(row, 0, false);
47653 this.scroller.dom.scrollLeft = x;
47657 * Focuses the specified cell.
47658 * @param {Number} row The row index
47659 * @param {Number} col The column index
47660 * @param {Boolean} hscroll false to disable horizontal scrolling
47662 focusCell : function(row, col, hscroll){
47663 var el = this.ensureVisible(row, col, hscroll);
47664 this.focusEl.alignTo(el, "tl-tl");
47666 this.focusEl.focus();
47668 this.focusEl.focus.defer(1, this.focusEl);
47673 * Scrolls the specified cell into view
47674 * @param {Number} row The row index
47675 * @param {Number} col The column index
47676 * @param {Boolean} hscroll false to disable horizontal scrolling
47678 ensureVisible : function(row, col, hscroll){
47679 if(typeof row != "number"){
47680 row = row.rowIndex;
47682 if(row < 0 && row >= this.ds.getCount()){
47685 col = (col !== undefined ? col : 0);
47686 var cm = this.grid.colModel;
47687 while(cm.isHidden(col)){
47691 var el = this.getCell(row, col);
47695 var c = this.scroller.dom;
47697 var ctop = parseInt(el.offsetTop, 10);
47698 var cleft = parseInt(el.offsetLeft, 10);
47699 var cbot = ctop + el.offsetHeight;
47700 var cright = cleft + el.offsetWidth;
47702 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47703 var stop = parseInt(c.scrollTop, 10);
47704 var sleft = parseInt(c.scrollLeft, 10);
47705 var sbot = stop + ch;
47706 var sright = sleft + c.clientWidth;
47709 c.scrollTop = ctop;
47710 }else if(cbot > sbot){
47711 c.scrollTop = cbot-ch;
47714 if(hscroll !== false){
47716 c.scrollLeft = cleft;
47717 }else if(cright > sright){
47718 c.scrollLeft = cright-c.clientWidth;
47724 updateColumns : function(){
47725 this.grid.stopEditing();
47726 var cm = this.grid.colModel, colIds = this.getColumnIds();
47727 //var totalWidth = cm.getTotalWidth();
47729 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47730 //if(cm.isHidden(i)) continue;
47731 var w = cm.getColumnWidth(i);
47732 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47733 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47735 this.updateSplitters();
47738 generateRules : function(cm){
47739 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
47740 Roo.util.CSS.removeStyleSheet(rulesId);
47741 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47742 var cid = cm.getColumnId(i);
47744 if(cm.config[i].align){
47745 align = 'text-align:'+cm.config[i].align+';';
47748 if(cm.isHidden(i)){
47749 hidden = 'display:none;';
47751 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
47753 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
47754 this.hdSelector, cid, " {\n", align, width, "}\n",
47755 this.tdSelector, cid, " {\n",hidden,"\n}\n",
47756 this.splitSelector, cid, " {\n", hidden , "\n}\n");
47758 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47761 updateSplitters : function(){
47762 var cm = this.cm, s = this.getSplitters();
47763 if(s){ // splitters not created yet
47764 var pos = 0, locked = true;
47765 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47766 if(cm.isHidden(i)) continue;
47767 var w = cm.getColumnWidth(i);
47768 if(!cm.isLocked(i) && locked){
47773 s[i].style.left = (pos-this.splitOffset) + "px";
47778 handleHiddenChange : function(colModel, colIndex, hidden){
47780 this.hideColumn(colIndex);
47782 this.unhideColumn(colIndex);
47786 hideColumn : function(colIndex){
47787 var cid = this.getColumnId(colIndex);
47788 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
47789 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
47791 this.updateHeaders();
47793 this.updateSplitters();
47797 unhideColumn : function(colIndex){
47798 var cid = this.getColumnId(colIndex);
47799 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
47800 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
47803 this.updateHeaders();
47805 this.updateSplitters();
47809 insertRows : function(dm, firstRow, lastRow, isUpdate){
47810 if(firstRow == 0 && lastRow == dm.getCount()-1){
47814 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
47816 var s = this.getScrollState();
47817 var markup = this.renderRows(firstRow, lastRow);
47818 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
47819 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
47820 this.restoreScroll(s);
47822 this.fireEvent("rowsinserted", this, firstRow, lastRow);
47823 this.syncRowHeights(firstRow, lastRow);
47824 this.stripeRows(firstRow);
47830 bufferRows : function(markup, target, index){
47831 var before = null, trows = target.rows, tbody = target.tBodies[0];
47832 if(index < trows.length){
47833 before = trows[index];
47835 var b = document.createElement("div");
47836 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
47837 var rows = b.firstChild.rows;
47838 for(var i = 0, len = rows.length; i < len; i++){
47840 tbody.insertBefore(rows[0], before);
47842 tbody.appendChild(rows[0]);
47849 deleteRows : function(dm, firstRow, lastRow){
47850 if(dm.getRowCount()<1){
47851 this.fireEvent("beforerefresh", this);
47852 this.mainBody.update("");
47853 this.lockedBody.update("");
47854 this.fireEvent("refresh", this);
47856 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
47857 var bt = this.getBodyTable();
47858 var tbody = bt.firstChild;
47859 var rows = bt.rows;
47860 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
47861 tbody.removeChild(rows[firstRow]);
47863 this.stripeRows(firstRow);
47864 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
47868 updateRows : function(dataSource, firstRow, lastRow){
47869 var s = this.getScrollState();
47871 this.restoreScroll(s);
47874 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
47878 this.updateHeaderSortState();
47881 getScrollState : function(){
47882 var sb = this.scroller.dom;
47883 return {left: sb.scrollLeft, top: sb.scrollTop};
47886 stripeRows : function(startRow){
47887 if(!this.grid.stripeRows || this.ds.getCount() < 1){
47890 startRow = startRow || 0;
47891 var rows = this.getBodyTable().rows;
47892 var lrows = this.getLockedTable().rows;
47893 var cls = ' x-grid-row-alt ';
47894 for(var i = startRow, len = rows.length; i < len; i++){
47895 var row = rows[i], lrow = lrows[i];
47896 var isAlt = ((i+1) % 2 == 0);
47897 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
47898 if(isAlt == hasAlt){
47902 row.className += " x-grid-row-alt";
47904 row.className = row.className.replace("x-grid-row-alt", "");
47907 lrow.className = row.className;
47912 restoreScroll : function(state){
47913 var sb = this.scroller.dom;
47914 sb.scrollLeft = state.left;
47915 sb.scrollTop = state.top;
47919 syncScroll : function(){
47920 var sb = this.scroller.dom;
47921 var sh = this.mainHd.dom;
47922 var bs = this.mainBody.dom;
47923 var lv = this.lockedBody.dom;
47924 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
47925 lv.scrollTop = bs.scrollTop = sb.scrollTop;
47928 handleScroll : function(e){
47930 var sb = this.scroller.dom;
47931 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
47935 handleWheel : function(e){
47936 var d = e.getWheelDelta();
47937 this.scroller.dom.scrollTop -= d*22;
47938 // set this here to prevent jumpy scrolling on large tables
47939 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
47943 renderRows : function(startRow, endRow){
47944 // pull in all the crap needed to render rows
47945 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
47946 var colCount = cm.getColumnCount();
47948 if(ds.getCount() < 1){
47952 // build a map for all the columns
47954 for(var i = 0; i < colCount; i++){
47955 var name = cm.getDataIndex(i);
47957 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
47958 renderer : cm.getRenderer(i),
47959 id : cm.getColumnId(i),
47960 locked : cm.isLocked(i)
47964 startRow = startRow || 0;
47965 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
47967 // records to render
47968 var rs = ds.getRange(startRow, endRow);
47970 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
47973 // As much as I hate to duplicate code, this was branched because FireFox really hates
47974 // [].join("") on strings. The performance difference was substantial enough to
47975 // branch this function
47976 doRender : Roo.isGecko ?
47977 function(cs, rs, ds, startRow, colCount, stripe){
47978 var ts = this.templates, ct = ts.cell, rt = ts.row;
47980 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47982 var hasListener = this.grid.hasListener('rowclass');
47984 for(var j = 0, len = rs.length; j < len; j++){
47985 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
47986 for(var i = 0; i < colCount; i++){
47988 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47990 p.css = p.attr = "";
47991 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47992 if(p.value == undefined || p.value === "") p.value = " ";
47993 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47994 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47996 var markup = ct.apply(p);
48004 if(stripe && ((rowIndex+1) % 2 == 0)){
48005 alt.push("x-grid-row-alt")
48008 alt.push( " x-grid-dirty-row");
48011 if(this.getRowClass){
48012 alt.push(this.getRowClass(r, rowIndex));
48018 rowIndex : rowIndex,
48021 this.grid.fireEvent('rowclass', this, rowcfg);
48022 alt.push(rowcfg.rowClass);
48024 rp.alt = alt.join(" ");
48025 lbuf+= rt.apply(rp);
48027 buf+= rt.apply(rp);
48029 return [lbuf, buf];
48031 function(cs, rs, ds, startRow, colCount, stripe){
48032 var ts = this.templates, ct = ts.cell, rt = ts.row;
48034 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48035 var hasListener = this.grid.hasListener('rowclass');
48037 for(var j = 0, len = rs.length; j < len; j++){
48038 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
48039 for(var i = 0; i < colCount; i++){
48041 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48043 p.css = p.attr = "";
48044 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48045 if(p.value == undefined || p.value === "") p.value = " ";
48046 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48047 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48049 var markup = ct.apply(p);
48051 cb[cb.length] = markup;
48053 lcb[lcb.length] = markup;
48057 if(stripe && ((rowIndex+1) % 2 == 0)){
48058 alt.push( "x-grid-row-alt");
48061 alt.push(" x-grid-dirty-row");
48064 if(this.getRowClass){
48065 alt.push( this.getRowClass(r, rowIndex));
48071 rowIndex : rowIndex,
48074 this.grid.fireEvent('rowclass', this, rowcfg);
48075 alt.push(rowcfg.rowClass);
48077 rp.alt = alt.join(" ");
48078 rp.cells = lcb.join("");
48079 lbuf[lbuf.length] = rt.apply(rp);
48080 rp.cells = cb.join("");
48081 buf[buf.length] = rt.apply(rp);
48083 return [lbuf.join(""), buf.join("")];
48086 renderBody : function(){
48087 var markup = this.renderRows();
48088 var bt = this.templates.body;
48089 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48093 * Refreshes the grid
48094 * @param {Boolean} headersToo
48096 refresh : function(headersToo){
48097 this.fireEvent("beforerefresh", this);
48098 this.grid.stopEditing();
48099 var result = this.renderBody();
48100 this.lockedBody.update(result[0]);
48101 this.mainBody.update(result[1]);
48102 if(headersToo === true){
48103 this.updateHeaders();
48104 this.updateColumns();
48105 this.updateSplitters();
48106 this.updateHeaderSortState();
48108 this.syncRowHeights();
48110 this.fireEvent("refresh", this);
48113 handleColumnMove : function(cm, oldIndex, newIndex){
48114 this.indexMap = null;
48115 var s = this.getScrollState();
48116 this.refresh(true);
48117 this.restoreScroll(s);
48118 this.afterMove(newIndex);
48121 afterMove : function(colIndex){
48122 if(this.enableMoveAnim && Roo.enableFx){
48123 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48127 updateCell : function(dm, rowIndex, dataIndex){
48128 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48129 if(typeof colIndex == "undefined"){ // not present in grid
48132 var cm = this.grid.colModel;
48133 var cell = this.getCell(rowIndex, colIndex);
48134 var cellText = this.getCellText(rowIndex, colIndex);
48137 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48138 id : cm.getColumnId(colIndex),
48139 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48141 var renderer = cm.getRenderer(colIndex);
48142 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48143 if(typeof val == "undefined" || val === "") val = " ";
48144 cellText.innerHTML = val;
48145 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48146 this.syncRowHeights(rowIndex, rowIndex);
48149 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48151 if(this.grid.autoSizeHeaders){
48152 var h = this.getHeaderCellMeasure(colIndex);
48153 maxWidth = Math.max(maxWidth, h.scrollWidth);
48156 if(this.cm.isLocked(colIndex)){
48157 tb = this.getLockedTable();
48160 tb = this.getBodyTable();
48161 index = colIndex - this.cm.getLockedCount();
48164 var rows = tb.rows;
48165 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48166 for(var i = 0; i < stopIndex; i++){
48167 var cell = rows[i].childNodes[index].firstChild;
48168 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48171 return maxWidth + /*margin for error in IE*/ 5;
48174 * Autofit a column to its content.
48175 * @param {Number} colIndex
48176 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48178 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48179 if(this.cm.isHidden(colIndex)){
48180 return; // can't calc a hidden column
48183 var cid = this.cm.getColumnId(colIndex);
48184 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48185 if(this.grid.autoSizeHeaders){
48186 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48189 var newWidth = this.calcColumnWidth(colIndex);
48190 this.cm.setColumnWidth(colIndex,
48191 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48192 if(!suppressEvent){
48193 this.grid.fireEvent("columnresize", colIndex, newWidth);
48198 * Autofits all columns to their content and then expands to fit any extra space in the grid
48200 autoSizeColumns : function(){
48201 var cm = this.grid.colModel;
48202 var colCount = cm.getColumnCount();
48203 for(var i = 0; i < colCount; i++){
48204 this.autoSizeColumn(i, true, true);
48206 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48209 this.updateColumns();
48215 * Autofits all columns to the grid's width proportionate with their current size
48216 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48218 fitColumns : function(reserveScrollSpace){
48219 var cm = this.grid.colModel;
48220 var colCount = cm.getColumnCount();
48224 for (i = 0; i < colCount; i++){
48225 if(!cm.isHidden(i) && !cm.isFixed(i)){
48226 w = cm.getColumnWidth(i);
48232 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48233 if(reserveScrollSpace){
48236 var frac = (avail - cm.getTotalWidth())/width;
48237 while (cols.length){
48240 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48242 this.updateColumns();
48246 onRowSelect : function(rowIndex){
48247 var row = this.getRowComposite(rowIndex);
48248 row.addClass("x-grid-row-selected");
48251 onRowDeselect : function(rowIndex){
48252 var row = this.getRowComposite(rowIndex);
48253 row.removeClass("x-grid-row-selected");
48256 onCellSelect : function(row, col){
48257 var cell = this.getCell(row, col);
48259 Roo.fly(cell).addClass("x-grid-cell-selected");
48263 onCellDeselect : function(row, col){
48264 var cell = this.getCell(row, col);
48266 Roo.fly(cell).removeClass("x-grid-cell-selected");
48270 updateHeaderSortState : function(){
48271 var state = this.ds.getSortState();
48275 this.sortState = state;
48276 var sortColumn = this.cm.findColumnIndex(state.field);
48277 if(sortColumn != -1){
48278 var sortDir = state.direction;
48279 var sc = this.sortClasses;
48280 var hds = this.el.select(this.headerSelector).removeClass(sc);
48281 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48285 handleHeaderClick : function(g, index){
48286 if(this.headersDisabled){
48289 var dm = g.dataSource, cm = g.colModel;
48290 if(!cm.isSortable(index)){
48294 dm.sort(cm.getDataIndex(index));
48298 destroy : function(){
48300 this.colMenu.removeAll();
48301 Roo.menu.MenuMgr.unregister(this.colMenu);
48302 this.colMenu.getEl().remove();
48303 delete this.colMenu;
48306 this.hmenu.removeAll();
48307 Roo.menu.MenuMgr.unregister(this.hmenu);
48308 this.hmenu.getEl().remove();
48311 if(this.grid.enableColumnMove){
48312 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48314 for(var dd in dds){
48315 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48316 var elid = dds[dd].dragElId;
48318 Roo.get(elid).remove();
48319 } else if(dds[dd].config.isTarget){
48320 dds[dd].proxyTop.remove();
48321 dds[dd].proxyBottom.remove();
48324 if(Roo.dd.DDM.locationCache[dd]){
48325 delete Roo.dd.DDM.locationCache[dd];
48328 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48331 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48332 this.bind(null, null);
48333 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48336 handleLockChange : function(){
48337 this.refresh(true);
48340 onDenyColumnLock : function(){
48344 onDenyColumnHide : function(){
48348 handleHdMenuClick : function(item){
48349 var index = this.hdCtxIndex;
48350 var cm = this.cm, ds = this.ds;
48353 ds.sort(cm.getDataIndex(index), "ASC");
48356 ds.sort(cm.getDataIndex(index), "DESC");
48359 var lc = cm.getLockedCount();
48360 if(cm.getColumnCount(true) <= lc+1){
48361 this.onDenyColumnLock();
48365 cm.setLocked(index, true, true);
48366 cm.moveColumn(index, lc);
48367 this.grid.fireEvent("columnmove", index, lc);
48369 cm.setLocked(index, true);
48373 var lc = cm.getLockedCount();
48374 if((lc-1) != index){
48375 cm.setLocked(index, false, true);
48376 cm.moveColumn(index, lc-1);
48377 this.grid.fireEvent("columnmove", index, lc-1);
48379 cm.setLocked(index, false);
48383 index = cm.getIndexById(item.id.substr(4));
48385 if(item.checked && cm.getColumnCount(true) <= 1){
48386 this.onDenyColumnHide();
48389 cm.setHidden(index, item.checked);
48395 beforeColMenuShow : function(){
48396 var cm = this.cm, colCount = cm.getColumnCount();
48397 this.colMenu.removeAll();
48398 for(var i = 0; i < colCount; i++){
48399 this.colMenu.add(new Roo.menu.CheckItem({
48400 id: "col-"+cm.getColumnId(i),
48401 text: cm.getColumnHeader(i),
48402 checked: !cm.isHidden(i),
48408 handleHdCtx : function(g, index, e){
48410 var hd = this.getHeaderCell(index);
48411 this.hdCtxIndex = index;
48412 var ms = this.hmenu.items, cm = this.cm;
48413 ms.get("asc").setDisabled(!cm.isSortable(index));
48414 ms.get("desc").setDisabled(!cm.isSortable(index));
48415 if(this.grid.enableColLock !== false){
48416 ms.get("lock").setDisabled(cm.isLocked(index));
48417 ms.get("unlock").setDisabled(!cm.isLocked(index));
48419 this.hmenu.show(hd, "tl-bl");
48422 handleHdOver : function(e){
48423 var hd = this.findHeaderCell(e.getTarget());
48424 if(hd && !this.headersDisabled){
48425 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48426 this.fly(hd).addClass("x-grid-hd-over");
48431 handleHdOut : function(e){
48432 var hd = this.findHeaderCell(e.getTarget());
48434 this.fly(hd).removeClass("x-grid-hd-over");
48438 handleSplitDblClick : function(e, t){
48439 var i = this.getCellIndex(t);
48440 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48441 this.autoSizeColumn(i, true);
48446 render : function(){
48449 var colCount = cm.getColumnCount();
48451 if(this.grid.monitorWindowResize === true){
48452 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48454 var header = this.renderHeaders();
48455 var body = this.templates.body.apply({rows:""});
48456 var html = this.templates.master.apply({
48459 lockedHeader: header[0],
48463 //this.updateColumns();
48465 this.grid.getGridEl().dom.innerHTML = html;
48467 this.initElements();
48469 // a kludge to fix the random scolling effect in webkit
48470 this.el.on("scroll", function() {
48471 this.el.dom.scrollTop=0; // hopefully not recursive..
48474 this.scroller.on("scroll", this.handleScroll, this);
48475 this.lockedBody.on("mousewheel", this.handleWheel, this);
48476 this.mainBody.on("mousewheel", this.handleWheel, this);
48478 this.mainHd.on("mouseover", this.handleHdOver, this);
48479 this.mainHd.on("mouseout", this.handleHdOut, this);
48480 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48481 {delegate: "."+this.splitClass});
48483 this.lockedHd.on("mouseover", this.handleHdOver, this);
48484 this.lockedHd.on("mouseout", this.handleHdOut, this);
48485 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48486 {delegate: "."+this.splitClass});
48488 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48489 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48492 this.updateSplitters();
48494 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48495 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48496 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48499 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48500 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48502 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48503 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48505 if(this.grid.enableColLock !== false){
48506 this.hmenu.add('-',
48507 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48508 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48511 if(this.grid.enableColumnHide !== false){
48513 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48514 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48515 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48517 this.hmenu.add('-',
48518 {id:"columns", text: this.columnsText, menu: this.colMenu}
48521 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48523 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48526 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48527 this.dd = new Roo.grid.GridDragZone(this.grid, {
48528 ddGroup : this.grid.ddGroup || 'GridDD'
48533 for(var i = 0; i < colCount; i++){
48534 if(cm.isHidden(i)){
48535 this.hideColumn(i);
48537 if(cm.config[i].align){
48538 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48539 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48543 this.updateHeaderSortState();
48545 this.beforeInitialResize();
48548 // two part rendering gives faster view to the user
48549 this.renderPhase2.defer(1, this);
48552 renderPhase2 : function(){
48553 // render the rows now
48555 if(this.grid.autoSizeColumns){
48556 this.autoSizeColumns();
48560 beforeInitialResize : function(){
48564 onColumnSplitterMoved : function(i, w){
48565 this.userResized = true;
48566 var cm = this.grid.colModel;
48567 cm.setColumnWidth(i, w, true);
48568 var cid = cm.getColumnId(i);
48569 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48570 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48571 this.updateSplitters();
48573 this.grid.fireEvent("columnresize", i, w);
48576 syncRowHeights : function(startIndex, endIndex){
48577 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48578 startIndex = startIndex || 0;
48579 var mrows = this.getBodyTable().rows;
48580 var lrows = this.getLockedTable().rows;
48581 var len = mrows.length-1;
48582 endIndex = Math.min(endIndex || len, len);
48583 for(var i = startIndex; i <= endIndex; i++){
48584 var m = mrows[i], l = lrows[i];
48585 var h = Math.max(m.offsetHeight, l.offsetHeight);
48586 m.style.height = l.style.height = h + "px";
48591 layout : function(initialRender, is2ndPass){
48593 var auto = g.autoHeight;
48594 var scrollOffset = 16;
48595 var c = g.getGridEl(), cm = this.cm,
48596 expandCol = g.autoExpandColumn,
48598 //c.beginMeasure();
48600 if(!c.dom.offsetWidth){ // display:none?
48602 this.lockedWrap.show();
48603 this.mainWrap.show();
48608 var hasLock = this.cm.isLocked(0);
48610 var tbh = this.headerPanel.getHeight();
48611 var bbh = this.footerPanel.getHeight();
48614 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
48615 var newHeight = ch + c.getBorderWidth("tb");
48617 newHeight = Math.min(g.maxHeight, newHeight);
48619 c.setHeight(newHeight);
48623 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48626 var s = this.scroller;
48628 var csize = c.getSize(true);
48630 this.el.setSize(csize.width, csize.height);
48632 this.headerPanel.setWidth(csize.width);
48633 this.footerPanel.setWidth(csize.width);
48635 var hdHeight = this.mainHd.getHeight();
48636 var vw = csize.width;
48637 var vh = csize.height - (tbh + bbh);
48641 var bt = this.getBodyTable();
48642 var ltWidth = hasLock ?
48643 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
48645 var scrollHeight = bt.offsetHeight;
48646 var scrollWidth = ltWidth + bt.offsetWidth;
48647 var vscroll = false, hscroll = false;
48649 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
48651 var lw = this.lockedWrap, mw = this.mainWrap;
48652 var lb = this.lockedBody, mb = this.mainBody;
48654 setTimeout(function(){
48655 var t = s.dom.offsetTop;
48656 var w = s.dom.clientWidth,
48657 h = s.dom.clientHeight;
48660 lw.setSize(ltWidth, h);
48662 mw.setLeftTop(ltWidth, t);
48663 mw.setSize(w-ltWidth, h);
48665 lb.setHeight(h-hdHeight);
48666 mb.setHeight(h-hdHeight);
48668 if(is2ndPass !== true && !gv.userResized && expandCol){
48669 // high speed resize without full column calculation
48671 var ci = cm.getIndexById(expandCol);
48673 ci = cm.findColumnIndex(expandCol);
48675 ci = Math.max(0, ci); // make sure it's got at least the first col.
48676 var expandId = cm.getColumnId(ci);
48677 var tw = cm.getTotalWidth(false);
48678 var currentWidth = cm.getColumnWidth(ci);
48679 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
48680 if(currentWidth != cw){
48681 cm.setColumnWidth(ci, cw, true);
48682 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48683 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48684 gv.updateSplitters();
48685 gv.layout(false, true);
48697 onWindowResize : function(){
48698 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
48704 appendFooter : function(parentEl){
48708 sortAscText : "Sort Ascending",
48709 sortDescText : "Sort Descending",
48710 lockText : "Lock Column",
48711 unlockText : "Unlock Column",
48712 columnsText : "Columns"
48716 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
48717 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
48718 this.proxy.el.addClass('x-grid3-col-dd');
48721 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
48722 handleMouseDown : function(e){
48726 callHandleMouseDown : function(e){
48727 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
48732 * Ext JS Library 1.1.1
48733 * Copyright(c) 2006-2007, Ext JS, LLC.
48735 * Originally Released Under LGPL - original licence link has changed is not relivant.
48738 * <script type="text/javascript">
48742 // This is a support class used internally by the Grid components
48743 Roo.grid.SplitDragZone = function(grid, hd, hd2){
48745 this.view = grid.getView();
48746 this.proxy = this.view.resizeProxy;
48747 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
48748 "gridSplitters" + this.grid.getGridEl().id, {
48749 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
48751 this.setHandleElId(Roo.id(hd));
48752 this.setOuterHandleElId(Roo.id(hd2));
48753 this.scroll = false;
48755 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
48756 fly: Roo.Element.fly,
48758 b4StartDrag : function(x, y){
48759 this.view.headersDisabled = true;
48760 this.proxy.setHeight(this.view.mainWrap.getHeight());
48761 var w = this.cm.getColumnWidth(this.cellIndex);
48762 var minw = Math.max(w-this.grid.minColumnWidth, 0);
48763 this.resetConstraints();
48764 this.setXConstraint(minw, 1000);
48765 this.setYConstraint(0, 0);
48766 this.minX = x - minw;
48767 this.maxX = x + 1000;
48769 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
48773 handleMouseDown : function(e){
48774 ev = Roo.EventObject.setEvent(e);
48775 var t = this.fly(ev.getTarget());
48776 if(t.hasClass("x-grid-split")){
48777 this.cellIndex = this.view.getCellIndex(t.dom);
48778 this.split = t.dom;
48779 this.cm = this.grid.colModel;
48780 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
48781 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
48786 endDrag : function(e){
48787 this.view.headersDisabled = false;
48788 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
48789 var diff = endX - this.startPos;
48790 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
48793 autoOffset : function(){
48794 this.setDelta(0,0);
48798 * Ext JS Library 1.1.1
48799 * Copyright(c) 2006-2007, Ext JS, LLC.
48801 * Originally Released Under LGPL - original licence link has changed is not relivant.
48804 * <script type="text/javascript">
48808 // This is a support class used internally by the Grid components
48809 Roo.grid.GridDragZone = function(grid, config){
48810 this.view = grid.getView();
48811 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
48812 if(this.view.lockedBody){
48813 this.setHandleElId(Roo.id(this.view.mainBody.dom));
48814 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
48816 this.scroll = false;
48818 this.ddel = document.createElement('div');
48819 this.ddel.className = 'x-grid-dd-wrap';
48822 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
48823 ddGroup : "GridDD",
48825 getDragData : function(e){
48826 var t = Roo.lib.Event.getTarget(e);
48827 var rowIndex = this.view.findRowIndex(t);
48828 if(rowIndex !== false){
48829 var sm = this.grid.selModel;
48830 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
48831 // sm.mouseDown(e, t);
48833 if (e.hasModifier()){
48834 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
48836 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
48841 onInitDrag : function(e){
48842 var data = this.dragData;
48843 this.ddel.innerHTML = this.grid.getDragDropText();
48844 this.proxy.update(this.ddel);
48845 // fire start drag?
48848 afterRepair : function(){
48849 this.dragging = false;
48852 getRepairXY : function(e, data){
48856 onEndDrag : function(data, e){
48860 onValidDrop : function(dd, e, id){
48865 beforeInvalidDrop : function(e, id){
48870 * Ext JS Library 1.1.1
48871 * Copyright(c) 2006-2007, Ext JS, LLC.
48873 * Originally Released Under LGPL - original licence link has changed is not relivant.
48876 * <script type="text/javascript">
48881 * @class Roo.grid.ColumnModel
48882 * @extends Roo.util.Observable
48883 * This is the default implementation of a ColumnModel used by the Grid. It defines
48884 * the columns in the grid.
48887 var colModel = new Roo.grid.ColumnModel([
48888 {header: "Ticker", width: 60, sortable: true, locked: true},
48889 {header: "Company Name", width: 150, sortable: true},
48890 {header: "Market Cap.", width: 100, sortable: true},
48891 {header: "$ Sales", width: 100, sortable: true, renderer: money},
48892 {header: "Employees", width: 100, sortable: true, resizable: false}
48897 * The config options listed for this class are options which may appear in each
48898 * individual column definition.
48899 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
48901 * @param {Object} config An Array of column config objects. See this class's
48902 * config objects for details.
48904 Roo.grid.ColumnModel = function(config){
48906 * The config passed into the constructor
48908 this.config = config;
48911 // if no id, create one
48912 // if the column does not have a dataIndex mapping,
48913 // map it to the order it is in the config
48914 for(var i = 0, len = config.length; i < len; i++){
48916 if(typeof c.dataIndex == "undefined"){
48919 if(typeof c.renderer == "string"){
48920 c.renderer = Roo.util.Format[c.renderer];
48922 if(typeof c.id == "undefined"){
48925 if(c.editor && c.editor.xtype){
48926 c.editor = Roo.factory(c.editor, Roo.grid);
48928 if(c.editor && c.editor.isFormField){
48929 c.editor = new Roo.grid.GridEditor(c.editor);
48931 this.lookup[c.id] = c;
48935 * The width of columns which have no width specified (defaults to 100)
48938 this.defaultWidth = 100;
48941 * Default sortable of columns which have no sortable specified (defaults to false)
48944 this.defaultSortable = false;
48948 * @event widthchange
48949 * Fires when the width of a column changes.
48950 * @param {ColumnModel} this
48951 * @param {Number} columnIndex The column index
48952 * @param {Number} newWidth The new width
48954 "widthchange": true,
48956 * @event headerchange
48957 * Fires when the text of a header changes.
48958 * @param {ColumnModel} this
48959 * @param {Number} columnIndex The column index
48960 * @param {Number} newText The new header text
48962 "headerchange": true,
48964 * @event hiddenchange
48965 * Fires when a column is hidden or "unhidden".
48966 * @param {ColumnModel} this
48967 * @param {Number} columnIndex The column index
48968 * @param {Boolean} hidden true if hidden, false otherwise
48970 "hiddenchange": true,
48972 * @event columnmoved
48973 * Fires when a column is moved.
48974 * @param {ColumnModel} this
48975 * @param {Number} oldIndex
48976 * @param {Number} newIndex
48978 "columnmoved" : true,
48980 * @event columlockchange
48981 * Fires when a column's locked state is changed
48982 * @param {ColumnModel} this
48983 * @param {Number} colIndex
48984 * @param {Boolean} locked true if locked
48986 "columnlockchange" : true
48988 Roo.grid.ColumnModel.superclass.constructor.call(this);
48990 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
48992 * @cfg {String} header The header text to display in the Grid view.
48995 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
48996 * {@link Roo.data.Record} definition from which to draw the column's value. If not
48997 * specified, the column's index is used as an index into the Record's data Array.
49000 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
49001 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
49004 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
49005 * Defaults to the value of the {@link #defaultSortable} property.
49006 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
49009 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
49012 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
49015 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
49018 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
49021 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
49022 * given the cell's data value. See {@link #setRenderer}. If not specified, the
49023 * default renderer uses the raw data value.
49026 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
49029 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
49033 * Returns the id of the column at the specified index.
49034 * @param {Number} index The column index
49035 * @return {String} the id
49037 getColumnId : function(index){
49038 return this.config[index].id;
49042 * Returns the column for a specified id.
49043 * @param {String} id The column id
49044 * @return {Object} the column
49046 getColumnById : function(id){
49047 return this.lookup[id];
49052 * Returns the column for a specified dataIndex.
49053 * @param {String} dataIndex The column dataIndex
49054 * @return {Object|Boolean} the column or false if not found
49056 getColumnByDataIndex: function(dataIndex){
49057 var index = this.findColumnIndex(dataIndex);
49058 return index > -1 ? this.config[index] : false;
49062 * Returns the index for a specified column id.
49063 * @param {String} id The column id
49064 * @return {Number} the index, or -1 if not found
49066 getIndexById : function(id){
49067 for(var i = 0, len = this.config.length; i < len; i++){
49068 if(this.config[i].id == id){
49076 * Returns the index for a specified column dataIndex.
49077 * @param {String} dataIndex The column dataIndex
49078 * @return {Number} the index, or -1 if not found
49081 findColumnIndex : function(dataIndex){
49082 for(var i = 0, len = this.config.length; i < len; i++){
49083 if(this.config[i].dataIndex == dataIndex){
49091 moveColumn : function(oldIndex, newIndex){
49092 var c = this.config[oldIndex];
49093 this.config.splice(oldIndex, 1);
49094 this.config.splice(newIndex, 0, c);
49095 this.dataMap = null;
49096 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49099 isLocked : function(colIndex){
49100 return this.config[colIndex].locked === true;
49103 setLocked : function(colIndex, value, suppressEvent){
49104 if(this.isLocked(colIndex) == value){
49107 this.config[colIndex].locked = value;
49108 if(!suppressEvent){
49109 this.fireEvent("columnlockchange", this, colIndex, value);
49113 getTotalLockedWidth : function(){
49114 var totalWidth = 0;
49115 for(var i = 0; i < this.config.length; i++){
49116 if(this.isLocked(i) && !this.isHidden(i)){
49117 this.totalWidth += this.getColumnWidth(i);
49123 getLockedCount : function(){
49124 for(var i = 0, len = this.config.length; i < len; i++){
49125 if(!this.isLocked(i)){
49132 * Returns the number of columns.
49135 getColumnCount : function(visibleOnly){
49136 if(visibleOnly === true){
49138 for(var i = 0, len = this.config.length; i < len; i++){
49139 if(!this.isHidden(i)){
49145 return this.config.length;
49149 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49150 * @param {Function} fn
49151 * @param {Object} scope (optional)
49152 * @return {Array} result
49154 getColumnsBy : function(fn, scope){
49156 for(var i = 0, len = this.config.length; i < len; i++){
49157 var c = this.config[i];
49158 if(fn.call(scope||this, c, i) === true){
49166 * Returns true if the specified column is sortable.
49167 * @param {Number} col The column index
49168 * @return {Boolean}
49170 isSortable : function(col){
49171 if(typeof this.config[col].sortable == "undefined"){
49172 return this.defaultSortable;
49174 return this.config[col].sortable;
49178 * Returns the rendering (formatting) function defined for the column.
49179 * @param {Number} col The column index.
49180 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49182 getRenderer : function(col){
49183 if(!this.config[col].renderer){
49184 return Roo.grid.ColumnModel.defaultRenderer;
49186 return this.config[col].renderer;
49190 * Sets the rendering (formatting) function for a column.
49191 * @param {Number} col The column index
49192 * @param {Function} fn The function to use to process the cell's raw data
49193 * to return HTML markup for the grid view. The render function is called with
49194 * the following parameters:<ul>
49195 * <li>Data value.</li>
49196 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49197 * <li>css A CSS style string to apply to the table cell.</li>
49198 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49199 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49200 * <li>Row index</li>
49201 * <li>Column index</li>
49202 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49204 setRenderer : function(col, fn){
49205 this.config[col].renderer = fn;
49209 * Returns the width for the specified column.
49210 * @param {Number} col The column index
49213 getColumnWidth : function(col){
49214 return this.config[col].width || this.defaultWidth;
49218 * Sets the width for a column.
49219 * @param {Number} col The column index
49220 * @param {Number} width The new width
49222 setColumnWidth : function(col, width, suppressEvent){
49223 this.config[col].width = width;
49224 this.totalWidth = null;
49225 if(!suppressEvent){
49226 this.fireEvent("widthchange", this, col, width);
49231 * Returns the total width of all columns.
49232 * @param {Boolean} includeHidden True to include hidden column widths
49235 getTotalWidth : function(includeHidden){
49236 if(!this.totalWidth){
49237 this.totalWidth = 0;
49238 for(var i = 0, len = this.config.length; i < len; i++){
49239 if(includeHidden || !this.isHidden(i)){
49240 this.totalWidth += this.getColumnWidth(i);
49244 return this.totalWidth;
49248 * Returns the header for the specified column.
49249 * @param {Number} col The column index
49252 getColumnHeader : function(col){
49253 return this.config[col].header;
49257 * Sets the header for a column.
49258 * @param {Number} col The column index
49259 * @param {String} header The new header
49261 setColumnHeader : function(col, header){
49262 this.config[col].header = header;
49263 this.fireEvent("headerchange", this, col, header);
49267 * Returns the tooltip for the specified column.
49268 * @param {Number} col The column index
49271 getColumnTooltip : function(col){
49272 return this.config[col].tooltip;
49275 * Sets the tooltip for a column.
49276 * @param {Number} col The column index
49277 * @param {String} tooltip The new tooltip
49279 setColumnTooltip : function(col, tooltip){
49280 this.config[col].tooltip = tooltip;
49284 * Returns the dataIndex for the specified column.
49285 * @param {Number} col The column index
49288 getDataIndex : function(col){
49289 return this.config[col].dataIndex;
49293 * Sets the dataIndex for a column.
49294 * @param {Number} col The column index
49295 * @param {Number} dataIndex The new dataIndex
49297 setDataIndex : function(col, dataIndex){
49298 this.config[col].dataIndex = dataIndex;
49304 * Returns true if the cell is editable.
49305 * @param {Number} colIndex The column index
49306 * @param {Number} rowIndex The row index
49307 * @return {Boolean}
49309 isCellEditable : function(colIndex, rowIndex){
49310 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49314 * Returns the editor defined for the cell/column.
49315 * return false or null to disable editing.
49316 * @param {Number} colIndex The column index
49317 * @param {Number} rowIndex The row index
49320 getCellEditor : function(colIndex, rowIndex){
49321 return this.config[colIndex].editor;
49325 * Sets if a column is editable.
49326 * @param {Number} col The column index
49327 * @param {Boolean} editable True if the column is editable
49329 setEditable : function(col, editable){
49330 this.config[col].editable = editable;
49335 * Returns true if the column is hidden.
49336 * @param {Number} colIndex The column index
49337 * @return {Boolean}
49339 isHidden : function(colIndex){
49340 return this.config[colIndex].hidden;
49345 * Returns true if the column width cannot be changed
49347 isFixed : function(colIndex){
49348 return this.config[colIndex].fixed;
49352 * Returns true if the column can be resized
49353 * @return {Boolean}
49355 isResizable : function(colIndex){
49356 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49359 * Sets if a column is hidden.
49360 * @param {Number} colIndex The column index
49361 * @param {Boolean} hidden True if the column is hidden
49363 setHidden : function(colIndex, hidden){
49364 this.config[colIndex].hidden = hidden;
49365 this.totalWidth = null;
49366 this.fireEvent("hiddenchange", this, colIndex, hidden);
49370 * Sets the editor for a column.
49371 * @param {Number} col The column index
49372 * @param {Object} editor The editor object
49374 setEditor : function(col, editor){
49375 this.config[col].editor = editor;
49379 Roo.grid.ColumnModel.defaultRenderer = function(value){
49380 if(typeof value == "string" && value.length < 1){
49386 // Alias for backwards compatibility
49387 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49390 * Ext JS Library 1.1.1
49391 * Copyright(c) 2006-2007, Ext JS, LLC.
49393 * Originally Released Under LGPL - original licence link has changed is not relivant.
49396 * <script type="text/javascript">
49400 * @class Roo.grid.AbstractSelectionModel
49401 * @extends Roo.util.Observable
49402 * Abstract base class for grid SelectionModels. It provides the interface that should be
49403 * implemented by descendant classes. This class should not be directly instantiated.
49406 Roo.grid.AbstractSelectionModel = function(){
49407 this.locked = false;
49408 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49411 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49412 /** @ignore Called by the grid automatically. Do not call directly. */
49413 init : function(grid){
49419 * Locks the selections.
49422 this.locked = true;
49426 * Unlocks the selections.
49428 unlock : function(){
49429 this.locked = false;
49433 * Returns true if the selections are locked.
49434 * @return {Boolean}
49436 isLocked : function(){
49437 return this.locked;
49441 * Ext JS Library 1.1.1
49442 * Copyright(c) 2006-2007, Ext JS, LLC.
49444 * Originally Released Under LGPL - original licence link has changed is not relivant.
49447 * <script type="text/javascript">
49450 * @extends Roo.grid.AbstractSelectionModel
49451 * @class Roo.grid.RowSelectionModel
49452 * The default SelectionModel used by {@link Roo.grid.Grid}.
49453 * It supports multiple selections and keyboard selection/navigation.
49455 * @param {Object} config
49457 Roo.grid.RowSelectionModel = function(config){
49458 Roo.apply(this, config);
49459 this.selections = new Roo.util.MixedCollection(false, function(o){
49464 this.lastActive = false;
49468 * @event selectionchange
49469 * Fires when the selection changes
49470 * @param {SelectionModel} this
49472 "selectionchange" : true,
49474 * @event afterselectionchange
49475 * Fires after the selection changes (eg. by key press or clicking)
49476 * @param {SelectionModel} this
49478 "afterselectionchange" : true,
49480 * @event beforerowselect
49481 * Fires when a row is selected being selected, return false to cancel.
49482 * @param {SelectionModel} this
49483 * @param {Number} rowIndex The selected index
49484 * @param {Boolean} keepExisting False if other selections will be cleared
49486 "beforerowselect" : true,
49489 * Fires when a row is selected.
49490 * @param {SelectionModel} this
49491 * @param {Number} rowIndex The selected index
49492 * @param {Roo.data.Record} r The record
49494 "rowselect" : true,
49496 * @event rowdeselect
49497 * Fires when a row is deselected.
49498 * @param {SelectionModel} this
49499 * @param {Number} rowIndex The selected index
49501 "rowdeselect" : true
49503 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49504 this.locked = false;
49507 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49509 * @cfg {Boolean} singleSelect
49510 * True to allow selection of only one row at a time (defaults to false)
49512 singleSelect : false,
49515 initEvents : function(){
49517 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49518 this.grid.on("mousedown", this.handleMouseDown, this);
49519 }else{ // allow click to work like normal
49520 this.grid.on("rowclick", this.handleDragableRowClick, this);
49523 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49524 "up" : function(e){
49526 this.selectPrevious(e.shiftKey);
49527 }else if(this.last !== false && this.lastActive !== false){
49528 var last = this.last;
49529 this.selectRange(this.last, this.lastActive-1);
49530 this.grid.getView().focusRow(this.lastActive);
49531 if(last !== false){
49535 this.selectFirstRow();
49537 this.fireEvent("afterselectionchange", this);
49539 "down" : function(e){
49541 this.selectNext(e.shiftKey);
49542 }else if(this.last !== false && this.lastActive !== false){
49543 var last = this.last;
49544 this.selectRange(this.last, this.lastActive+1);
49545 this.grid.getView().focusRow(this.lastActive);
49546 if(last !== false){
49550 this.selectFirstRow();
49552 this.fireEvent("afterselectionchange", this);
49557 var view = this.grid.view;
49558 view.on("refresh", this.onRefresh, this);
49559 view.on("rowupdated", this.onRowUpdated, this);
49560 view.on("rowremoved", this.onRemove, this);
49564 onRefresh : function(){
49565 var ds = this.grid.dataSource, i, v = this.grid.view;
49566 var s = this.selections;
49567 s.each(function(r){
49568 if((i = ds.indexOfId(r.id)) != -1){
49577 onRemove : function(v, index, r){
49578 this.selections.remove(r);
49582 onRowUpdated : function(v, index, r){
49583 if(this.isSelected(r)){
49584 v.onRowSelect(index);
49590 * @param {Array} records The records to select
49591 * @param {Boolean} keepExisting (optional) True to keep existing selections
49593 selectRecords : function(records, keepExisting){
49595 this.clearSelections();
49597 var ds = this.grid.dataSource;
49598 for(var i = 0, len = records.length; i < len; i++){
49599 this.selectRow(ds.indexOf(records[i]), true);
49604 * Gets the number of selected rows.
49607 getCount : function(){
49608 return this.selections.length;
49612 * Selects the first row in the grid.
49614 selectFirstRow : function(){
49619 * Select the last row.
49620 * @param {Boolean} keepExisting (optional) True to keep existing selections
49622 selectLastRow : function(keepExisting){
49623 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
49627 * Selects the row immediately following the last selected row.
49628 * @param {Boolean} keepExisting (optional) True to keep existing selections
49630 selectNext : function(keepExisting){
49631 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49632 this.selectRow(this.last+1, keepExisting);
49633 this.grid.getView().focusRow(this.last);
49638 * Selects the row that precedes the last selected row.
49639 * @param {Boolean} keepExisting (optional) True to keep existing selections
49641 selectPrevious : function(keepExisting){
49643 this.selectRow(this.last-1, keepExisting);
49644 this.grid.getView().focusRow(this.last);
49649 * Returns the selected records
49650 * @return {Array} Array of selected records
49652 getSelections : function(){
49653 return [].concat(this.selections.items);
49657 * Returns the first selected record.
49660 getSelected : function(){
49661 return this.selections.itemAt(0);
49666 * Clears all selections.
49668 clearSelections : function(fast){
49669 if(this.locked) return;
49671 var ds = this.grid.dataSource;
49672 var s = this.selections;
49673 s.each(function(r){
49674 this.deselectRow(ds.indexOfId(r.id));
49678 this.selections.clear();
49685 * Selects all rows.
49687 selectAll : function(){
49688 if(this.locked) return;
49689 this.selections.clear();
49690 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
49691 this.selectRow(i, true);
49696 * Returns True if there is a selection.
49697 * @return {Boolean}
49699 hasSelection : function(){
49700 return this.selections.length > 0;
49704 * Returns True if the specified row is selected.
49705 * @param {Number/Record} record The record or index of the record to check
49706 * @return {Boolean}
49708 isSelected : function(index){
49709 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
49710 return (r && this.selections.key(r.id) ? true : false);
49714 * Returns True if the specified record id is selected.
49715 * @param {String} id The id of record to check
49716 * @return {Boolean}
49718 isIdSelected : function(id){
49719 return (this.selections.key(id) ? true : false);
49723 handleMouseDown : function(e, t){
49724 var view = this.grid.getView(), rowIndex;
49725 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
49728 if(e.shiftKey && this.last !== false){
49729 var last = this.last;
49730 this.selectRange(last, rowIndex, e.ctrlKey);
49731 this.last = last; // reset the last
49732 view.focusRow(rowIndex);
49734 var isSelected = this.isSelected(rowIndex);
49735 if(e.button !== 0 && isSelected){
49736 view.focusRow(rowIndex);
49737 }else if(e.ctrlKey && isSelected){
49738 this.deselectRow(rowIndex);
49739 }else if(!isSelected){
49740 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
49741 view.focusRow(rowIndex);
49744 this.fireEvent("afterselectionchange", this);
49747 handleDragableRowClick : function(grid, rowIndex, e)
49749 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
49750 this.selectRow(rowIndex, false);
49751 grid.view.focusRow(rowIndex);
49752 this.fireEvent("afterselectionchange", this);
49757 * Selects multiple rows.
49758 * @param {Array} rows Array of the indexes of the row to select
49759 * @param {Boolean} keepExisting (optional) True to keep existing selections
49761 selectRows : function(rows, keepExisting){
49763 this.clearSelections();
49765 for(var i = 0, len = rows.length; i < len; i++){
49766 this.selectRow(rows[i], true);
49771 * Selects a range of rows. All rows in between startRow and endRow are also selected.
49772 * @param {Number} startRow The index of the first row in the range
49773 * @param {Number} endRow The index of the last row in the range
49774 * @param {Boolean} keepExisting (optional) True to retain existing selections
49776 selectRange : function(startRow, endRow, keepExisting){
49777 if(this.locked) return;
49779 this.clearSelections();
49781 if(startRow <= endRow){
49782 for(var i = startRow; i <= endRow; i++){
49783 this.selectRow(i, true);
49786 for(var i = startRow; i >= endRow; i--){
49787 this.selectRow(i, true);
49793 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
49794 * @param {Number} startRow The index of the first row in the range
49795 * @param {Number} endRow The index of the last row in the range
49797 deselectRange : function(startRow, endRow, preventViewNotify){
49798 if(this.locked) return;
49799 for(var i = startRow; i <= endRow; i++){
49800 this.deselectRow(i, preventViewNotify);
49806 * @param {Number} row The index of the row to select
49807 * @param {Boolean} keepExisting (optional) True to keep existing selections
49809 selectRow : function(index, keepExisting, preventViewNotify){
49810 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
49811 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
49812 if(!keepExisting || this.singleSelect){
49813 this.clearSelections();
49815 var r = this.grid.dataSource.getAt(index);
49816 this.selections.add(r);
49817 this.last = this.lastActive = index;
49818 if(!preventViewNotify){
49819 this.grid.getView().onRowSelect(index);
49821 this.fireEvent("rowselect", this, index, r);
49822 this.fireEvent("selectionchange", this);
49828 * @param {Number} row The index of the row to deselect
49830 deselectRow : function(index, preventViewNotify){
49831 if(this.locked) return;
49832 if(this.last == index){
49835 if(this.lastActive == index){
49836 this.lastActive = false;
49838 var r = this.grid.dataSource.getAt(index);
49839 this.selections.remove(r);
49840 if(!preventViewNotify){
49841 this.grid.getView().onRowDeselect(index);
49843 this.fireEvent("rowdeselect", this, index);
49844 this.fireEvent("selectionchange", this);
49848 restoreLast : function(){
49850 this.last = this._last;
49855 acceptsNav : function(row, col, cm){
49856 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49860 onEditorKey : function(field, e){
49861 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49866 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49868 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49870 }else if(k == e.ENTER && !e.ctrlKey){
49874 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
49876 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
49878 }else if(k == e.ESC){
49882 g.startEditing(newCell[0], newCell[1]);
49887 * Ext JS Library 1.1.1
49888 * Copyright(c) 2006-2007, Ext JS, LLC.
49890 * Originally Released Under LGPL - original licence link has changed is not relivant.
49893 * <script type="text/javascript">
49896 * @class Roo.grid.CellSelectionModel
49897 * @extends Roo.grid.AbstractSelectionModel
49898 * This class provides the basic implementation for cell selection in a grid.
49900 * @param {Object} config The object containing the configuration of this model.
49902 Roo.grid.CellSelectionModel = function(config){
49903 Roo.apply(this, config);
49905 this.selection = null;
49909 * @event beforerowselect
49910 * Fires before a cell is selected.
49911 * @param {SelectionModel} this
49912 * @param {Number} rowIndex The selected row index
49913 * @param {Number} colIndex The selected cell index
49915 "beforecellselect" : true,
49917 * @event cellselect
49918 * Fires when a cell is selected.
49919 * @param {SelectionModel} this
49920 * @param {Number} rowIndex The selected row index
49921 * @param {Number} colIndex The selected cell index
49923 "cellselect" : true,
49925 * @event selectionchange
49926 * Fires when the active selection changes.
49927 * @param {SelectionModel} this
49928 * @param {Object} selection null for no selection or an object (o) with two properties
49930 <li>o.record: the record object for the row the selection is in</li>
49931 <li>o.cell: An array of [rowIndex, columnIndex]</li>
49934 "selectionchange" : true
49936 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
49939 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
49942 initEvents : function(){
49943 this.grid.on("mousedown", this.handleMouseDown, this);
49944 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
49945 var view = this.grid.view;
49946 view.on("refresh", this.onViewChange, this);
49947 view.on("rowupdated", this.onRowUpdated, this);
49948 view.on("beforerowremoved", this.clearSelections, this);
49949 view.on("beforerowsinserted", this.clearSelections, this);
49950 if(this.grid.isEditor){
49951 this.grid.on("beforeedit", this.beforeEdit, this);
49956 beforeEdit : function(e){
49957 this.select(e.row, e.column, false, true, e.record);
49961 onRowUpdated : function(v, index, r){
49962 if(this.selection && this.selection.record == r){
49963 v.onCellSelect(index, this.selection.cell[1]);
49968 onViewChange : function(){
49969 this.clearSelections(true);
49973 * Returns the currently selected cell,.
49974 * @return {Array} The selected cell (row, column) or null if none selected.
49976 getSelectedCell : function(){
49977 return this.selection ? this.selection.cell : null;
49981 * Clears all selections.
49982 * @param {Boolean} true to prevent the gridview from being notified about the change.
49984 clearSelections : function(preventNotify){
49985 var s = this.selection;
49987 if(preventNotify !== true){
49988 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
49990 this.selection = null;
49991 this.fireEvent("selectionchange", this, null);
49996 * Returns true if there is a selection.
49997 * @return {Boolean}
49999 hasSelection : function(){
50000 return this.selection ? true : false;
50004 handleMouseDown : function(e, t){
50005 var v = this.grid.getView();
50006 if(this.isLocked()){
50009 var row = v.findRowIndex(t);
50010 var cell = v.findCellIndex(t);
50011 if(row !== false && cell !== false){
50012 this.select(row, cell);
50018 * @param {Number} rowIndex
50019 * @param {Number} collIndex
50021 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
50022 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
50023 this.clearSelections();
50024 r = r || this.grid.dataSource.getAt(rowIndex);
50027 cell : [rowIndex, colIndex]
50029 if(!preventViewNotify){
50030 var v = this.grid.getView();
50031 v.onCellSelect(rowIndex, colIndex);
50032 if(preventFocus !== true){
50033 v.focusCell(rowIndex, colIndex);
50036 this.fireEvent("cellselect", this, rowIndex, colIndex);
50037 this.fireEvent("selectionchange", this, this.selection);
50042 isSelectable : function(rowIndex, colIndex, cm){
50043 return !cm.isHidden(colIndex);
50047 handleKeyDown : function(e){
50048 Roo.log('Cell Sel Model handleKeyDown');
50049 if(!e.isNavKeyPress()){
50052 var g = this.grid, s = this.selection;
50055 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
50057 this.select(cell[0], cell[1]);
50062 var walk = function(row, col, step){
50063 return g.walkCells(row, col, step, sm.isSelectable, sm);
50065 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
50070 // handled by onEditorKey
50071 if (g.isEditor && g.editing) {
50075 newCell = walk(r, c-1, -1);
50077 newCell = walk(r, c+1, 1);
50081 newCell = walk(r+1, c, 1);
50084 newCell = walk(r-1, c, -1);
50087 newCell = walk(r, c+1, 1);
50090 newCell = walk(r, c-1, -1);
50093 if(g.isEditor && !g.editing){
50094 g.startEditing(r, c);
50101 this.select(newCell[0], newCell[1]);
50106 acceptsNav : function(row, col, cm){
50107 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50110 onEditorKey : function(field, e){
50112 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50113 ///Roo.log('onEditorKey' + k);
50117 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50119 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50122 }else if(k == e.ENTER && !e.ctrlKey){
50125 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50126 }else if(k == e.ESC){
50132 //Roo.log('next cell after edit');
50133 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50138 * Ext JS Library 1.1.1
50139 * Copyright(c) 2006-2007, Ext JS, LLC.
50141 * Originally Released Under LGPL - original licence link has changed is not relivant.
50144 * <script type="text/javascript">
50148 * @class Roo.grid.EditorGrid
50149 * @extends Roo.grid.Grid
50150 * Class for creating and editable grid.
50151 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50152 * The container MUST have some type of size defined for the grid to fill. The container will be
50153 * automatically set to position relative if it isn't already.
50154 * @param {Object} dataSource The data model to bind to
50155 * @param {Object} colModel The column model with info about this grid's columns
50157 Roo.grid.EditorGrid = function(container, config){
50158 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50159 this.getGridEl().addClass("xedit-grid");
50161 if(!this.selModel){
50162 this.selModel = new Roo.grid.CellSelectionModel();
50165 this.activeEditor = null;
50169 * @event beforeedit
50170 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50171 * <ul style="padding:5px;padding-left:16px;">
50172 * <li>grid - This grid</li>
50173 * <li>record - The record being edited</li>
50174 * <li>field - The field name being edited</li>
50175 * <li>value - The value for the field being edited.</li>
50176 * <li>row - The grid row index</li>
50177 * <li>column - The grid column index</li>
50178 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50180 * @param {Object} e An edit event (see above for description)
50182 "beforeedit" : true,
50185 * Fires after a cell is edited. <br />
50186 * <ul style="padding:5px;padding-left:16px;">
50187 * <li>grid - This grid</li>
50188 * <li>record - The record being edited</li>
50189 * <li>field - The field name being edited</li>
50190 * <li>value - The value being set</li>
50191 * <li>originalValue - The original value for the field, before the edit.</li>
50192 * <li>row - The grid row index</li>
50193 * <li>column - The grid column index</li>
50195 * @param {Object} e An edit event (see above for description)
50197 "afteredit" : true,
50199 * @event validateedit
50200 * Fires after a cell is edited, but before the value is set in the record.
50201 * You can use this to modify the value being set in the field, Return false
50202 * to cancel the change. The edit event object has the following properties <br />
50203 * <ul style="padding:5px;padding-left:16px;">
50204 * <li>editor - This editor</li>
50205 * <li>grid - This grid</li>
50206 * <li>record - The record being edited</li>
50207 * <li>field - The field name being edited</li>
50208 * <li>value - The value being set</li>
50209 * <li>originalValue - The original value for the field, before the edit.</li>
50210 * <li>row - The grid row index</li>
50211 * <li>column - The grid column index</li>
50212 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50214 * @param {Object} e An edit event (see above for description)
50216 "validateedit" : true
50218 this.on("bodyscroll", this.stopEditing, this);
50219 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50222 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50224 * @cfg {Number} clicksToEdit
50225 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50232 trackMouseOver: false, // causes very odd FF errors
50234 onCellDblClick : function(g, row, col){
50235 this.startEditing(row, col);
50238 onEditComplete : function(ed, value, startValue){
50239 this.editing = false;
50240 this.activeEditor = null;
50241 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50243 var field = this.colModel.getDataIndex(ed.col);
50248 originalValue: startValue,
50255 if(String(value) !== String(startValue)){
50257 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50258 r.set(field, e.value);
50259 // if we are dealing with a combo box..
50260 // then we also set the 'name' colum to be the displayField
50261 if (ed.field.displayField && ed.field.name) {
50262 r.set(ed.field.name, ed.field.el.dom.value);
50265 delete e.cancel; //?? why!!!
50266 this.fireEvent("afteredit", e);
50269 this.fireEvent("afteredit", e); // always fire it!
50271 this.view.focusCell(ed.row, ed.col);
50275 * Starts editing the specified for the specified row/column
50276 * @param {Number} rowIndex
50277 * @param {Number} colIndex
50279 startEditing : function(row, col){
50280 this.stopEditing();
50281 if(this.colModel.isCellEditable(col, row)){
50282 this.view.ensureVisible(row, col, true);
50283 var r = this.dataSource.getAt(row);
50284 var field = this.colModel.getDataIndex(col);
50289 value: r.data[field],
50294 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50295 this.editing = true;
50296 var ed = this.colModel.getCellEditor(col, row);
50302 ed.render(ed.parentEl || document.body);
50305 (function(){ // complex but required for focus issues in safari, ie and opera
50309 ed.on("complete", this.onEditComplete, this, {single: true});
50310 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50311 this.activeEditor = ed;
50312 var v = r.data[field];
50313 ed.startEdit(this.view.getCell(row, col), v);
50314 // combo's with 'displayField and name set
50315 if (ed.field.displayField && ed.field.name) {
50316 ed.field.el.dom.value = r.data[ed.field.name];
50320 }).defer(50, this);
50326 * Stops any active editing
50328 stopEditing : function(){
50329 if(this.activeEditor){
50330 this.activeEditor.completeEdit();
50332 this.activeEditor = null;
50336 * Ext JS Library 1.1.1
50337 * Copyright(c) 2006-2007, Ext JS, LLC.
50339 * Originally Released Under LGPL - original licence link has changed is not relivant.
50342 * <script type="text/javascript">
50345 // private - not really -- you end up using it !
50346 // This is a support class used internally by the Grid components
50349 * @class Roo.grid.GridEditor
50350 * @extends Roo.Editor
50351 * Class for creating and editable grid elements.
50352 * @param {Object} config any settings (must include field)
50354 Roo.grid.GridEditor = function(field, config){
50355 if (!config && field.field) {
50357 field = Roo.factory(config.field, Roo.form);
50359 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50360 field.monitorTab = false;
50363 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50366 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50369 alignment: "tl-tl",
50372 cls: "x-small-editor x-grid-editor",
50377 * Ext JS Library 1.1.1
50378 * Copyright(c) 2006-2007, Ext JS, LLC.
50380 * Originally Released Under LGPL - original licence link has changed is not relivant.
50383 * <script type="text/javascript">
50388 Roo.grid.PropertyRecord = Roo.data.Record.create([
50389 {name:'name',type:'string'}, 'value'
50393 Roo.grid.PropertyStore = function(grid, source){
50395 this.store = new Roo.data.Store({
50396 recordType : Roo.grid.PropertyRecord
50398 this.store.on('update', this.onUpdate, this);
50400 this.setSource(source);
50402 Roo.grid.PropertyStore.superclass.constructor.call(this);
50407 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50408 setSource : function(o){
50410 this.store.removeAll();
50413 if(this.isEditableValue(o[k])){
50414 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50417 this.store.loadRecords({records: data}, {}, true);
50420 onUpdate : function(ds, record, type){
50421 if(type == Roo.data.Record.EDIT){
50422 var v = record.data['value'];
50423 var oldValue = record.modified['value'];
50424 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50425 this.source[record.id] = v;
50427 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50434 getProperty : function(row){
50435 return this.store.getAt(row);
50438 isEditableValue: function(val){
50439 if(val && val instanceof Date){
50441 }else if(typeof val == 'object' || typeof val == 'function'){
50447 setValue : function(prop, value){
50448 this.source[prop] = value;
50449 this.store.getById(prop).set('value', value);
50452 getSource : function(){
50453 return this.source;
50457 Roo.grid.PropertyColumnModel = function(grid, store){
50460 g.PropertyColumnModel.superclass.constructor.call(this, [
50461 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50462 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50464 this.store = store;
50465 this.bselect = Roo.DomHelper.append(document.body, {
50466 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50467 {tag: 'option', value: 'true', html: 'true'},
50468 {tag: 'option', value: 'false', html: 'false'}
50471 Roo.id(this.bselect);
50474 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50475 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50476 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50477 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50478 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50480 this.renderCellDelegate = this.renderCell.createDelegate(this);
50481 this.renderPropDelegate = this.renderProp.createDelegate(this);
50484 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50488 valueText : 'Value',
50490 dateFormat : 'm/j/Y',
50493 renderDate : function(dateVal){
50494 return dateVal.dateFormat(this.dateFormat);
50497 renderBool : function(bVal){
50498 return bVal ? 'true' : 'false';
50501 isCellEditable : function(colIndex, rowIndex){
50502 return colIndex == 1;
50505 getRenderer : function(col){
50507 this.renderCellDelegate : this.renderPropDelegate;
50510 renderProp : function(v){
50511 return this.getPropertyName(v);
50514 renderCell : function(val){
50516 if(val instanceof Date){
50517 rv = this.renderDate(val);
50518 }else if(typeof val == 'boolean'){
50519 rv = this.renderBool(val);
50521 return Roo.util.Format.htmlEncode(rv);
50524 getPropertyName : function(name){
50525 var pn = this.grid.propertyNames;
50526 return pn && pn[name] ? pn[name] : name;
50529 getCellEditor : function(colIndex, rowIndex){
50530 var p = this.store.getProperty(rowIndex);
50531 var n = p.data['name'], val = p.data['value'];
50533 if(typeof(this.grid.customEditors[n]) == 'string'){
50534 return this.editors[this.grid.customEditors[n]];
50536 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50537 return this.grid.customEditors[n];
50539 if(val instanceof Date){
50540 return this.editors['date'];
50541 }else if(typeof val == 'number'){
50542 return this.editors['number'];
50543 }else if(typeof val == 'boolean'){
50544 return this.editors['boolean'];
50546 return this.editors['string'];
50552 * @class Roo.grid.PropertyGrid
50553 * @extends Roo.grid.EditorGrid
50554 * This class represents the interface of a component based property grid control.
50555 * <br><br>Usage:<pre><code>
50556 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50564 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50565 * The container MUST have some type of size defined for the grid to fill. The container will be
50566 * automatically set to position relative if it isn't already.
50567 * @param {Object} config A config object that sets properties on this grid.
50569 Roo.grid.PropertyGrid = function(container, config){
50570 config = config || {};
50571 var store = new Roo.grid.PropertyStore(this);
50572 this.store = store;
50573 var cm = new Roo.grid.PropertyColumnModel(this, store);
50574 store.store.sort('name', 'ASC');
50575 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50578 enableColLock:false,
50579 enableColumnMove:false,
50581 trackMouseOver: false,
50584 this.getGridEl().addClass('x-props-grid');
50585 this.lastEditRow = null;
50586 this.on('columnresize', this.onColumnResize, this);
50589 * @event beforepropertychange
50590 * Fires before a property changes (return false to stop?)
50591 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50592 * @param {String} id Record Id
50593 * @param {String} newval New Value
50594 * @param {String} oldval Old Value
50596 "beforepropertychange": true,
50598 * @event propertychange
50599 * Fires after a property changes
50600 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50601 * @param {String} id Record Id
50602 * @param {String} newval New Value
50603 * @param {String} oldval Old Value
50605 "propertychange": true
50607 this.customEditors = this.customEditors || {};
50609 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50612 * @cfg {Object} customEditors map of colnames=> custom editors.
50613 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50614 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50615 * false disables editing of the field.
50619 * @cfg {Object} propertyNames map of property Names to their displayed value
50622 render : function(){
50623 Roo.grid.PropertyGrid.superclass.render.call(this);
50624 this.autoSize.defer(100, this);
50627 autoSize : function(){
50628 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50630 this.view.fitColumns();
50634 onColumnResize : function(){
50635 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
50639 * Sets the data for the Grid
50640 * accepts a Key => Value object of all the elements avaiable.
50641 * @param {Object} data to appear in grid.
50643 setSource : function(source){
50644 this.store.setSource(source);
50648 * Gets all the data from the grid.
50649 * @return {Object} data data stored in grid
50651 getSource : function(){
50652 return this.store.getSource();
50656 * Ext JS Library 1.1.1
50657 * Copyright(c) 2006-2007, Ext JS, LLC.
50659 * Originally Released Under LGPL - original licence link has changed is not relivant.
50662 * <script type="text/javascript">
50666 * @class Roo.LoadMask
50667 * A simple utility class for generically masking elements while loading data. If the element being masked has
50668 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
50669 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
50670 * element's UpdateManager load indicator and will be destroyed after the initial load.
50672 * Create a new LoadMask
50673 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
50674 * @param {Object} config The config object
50676 Roo.LoadMask = function(el, config){
50677 this.el = Roo.get(el);
50678 Roo.apply(this, config);
50680 this.store.on('beforeload', this.onBeforeLoad, this);
50681 this.store.on('load', this.onLoad, this);
50682 this.store.on('loadexception', this.onLoad, this);
50683 this.removeMask = false;
50685 var um = this.el.getUpdateManager();
50686 um.showLoadIndicator = false; // disable the default indicator
50687 um.on('beforeupdate', this.onBeforeLoad, this);
50688 um.on('update', this.onLoad, this);
50689 um.on('failure', this.onLoad, this);
50690 this.removeMask = true;
50694 Roo.LoadMask.prototype = {
50696 * @cfg {Boolean} removeMask
50697 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
50698 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
50701 * @cfg {String} msg
50702 * The text to display in a centered loading message box (defaults to 'Loading...')
50704 msg : 'Loading...',
50706 * @cfg {String} msgCls
50707 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
50709 msgCls : 'x-mask-loading',
50712 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
50718 * Disables the mask to prevent it from being displayed
50720 disable : function(){
50721 this.disabled = true;
50725 * Enables the mask so that it can be displayed
50727 enable : function(){
50728 this.disabled = false;
50732 onLoad : function(){
50733 this.el.unmask(this.removeMask);
50737 onBeforeLoad : function(){
50738 if(!this.disabled){
50739 this.el.mask(this.msg, this.msgCls);
50744 destroy : function(){
50746 this.store.un('beforeload', this.onBeforeLoad, this);
50747 this.store.un('load', this.onLoad, this);
50748 this.store.un('loadexception', this.onLoad, this);
50750 var um = this.el.getUpdateManager();
50751 um.un('beforeupdate', this.onBeforeLoad, this);
50752 um.un('update', this.onLoad, this);
50753 um.un('failure', this.onLoad, this);
50758 * Ext JS Library 1.1.1
50759 * Copyright(c) 2006-2007, Ext JS, LLC.
50761 * Originally Released Under LGPL - original licence link has changed is not relivant.
50764 * <script type="text/javascript">
50766 Roo.XTemplate = function(){
50767 Roo.XTemplate.superclass.constructor.apply(this, arguments);
50770 s = ['<tpl>', s, '</tpl>'].join('');
50772 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
50774 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
50775 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
50776 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
50780 while(m = s.match(re)){
50781 var m2 = m[0].match(nameRe);
50782 var m3 = m[0].match(ifRe);
50783 var m4 = m[0].match(execRe);
50784 var exp = null, fn = null, exec = null;
50785 var name = m2 && m2[1] ? m2[1] : '';
50787 exp = m3 && m3[1] ? m3[1] : null;
50789 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
50793 exp = m4 && m4[1] ? m4[1] : null;
50795 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
50800 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
50801 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
50802 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
50812 s = s.replace(m[0], '{xtpl'+ id + '}');
50815 for(var i = tpls.length-1; i >= 0; --i){
50816 this.compileTpl(tpls[i]);
50818 this.master = tpls[tpls.length-1];
50821 Roo.extend(Roo.XTemplate, Roo.Template, {
50823 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
50825 applySubTemplate : function(id, values, parent){
50826 var t = this.tpls[id];
50827 if(t.test && !t.test.call(this, values, parent)){
50830 if(t.exec && t.exec.call(this, values, parent)){
50833 var vs = t.target ? t.target.call(this, values, parent) : values;
50834 parent = t.target ? values : parent;
50835 if(t.target && vs instanceof Array){
50837 for(var i = 0, len = vs.length; i < len; i++){
50838 buf[buf.length] = t.compiled.call(this, vs[i], parent);
50840 return buf.join('');
50842 return t.compiled.call(this, vs, parent);
50845 compileTpl : function(tpl){
50846 var fm = Roo.util.Format;
50847 var useF = this.disableFormats !== true;
50848 var sep = Roo.isGecko ? "+" : ",";
50849 var fn = function(m, name, format, args){
50850 if(name.substr(0, 4) == 'xtpl'){
50851 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
50854 if(name.indexOf('.') != -1){
50857 v = "values['" + name + "']";
50859 if(format && useF){
50860 args = args ? ',' + args : "";
50861 if(format.substr(0, 5) != "this."){
50862 format = "fm." + format + '(';
50864 format = 'this.call("'+ format.substr(5) + '", ';
50868 args= ''; format = "("+v+" === undefined ? '' : ";
50870 return "'"+ sep + format + v + args + ")"+sep+"'";
50873 // branched to use + in gecko and [].join() in others
50875 body = "tpl.compiled = function(values, parent){ return '" +
50876 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
50879 body = ["tpl.compiled = function(values, parent){ return ['"];
50880 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
50881 body.push("'].join('');};");
50882 body = body.join('');
50884 /** eval:var:zzzzzzz */
50889 applyTemplate : function(values){
50890 return this.master.compiled.call(this, values, {});
50894 apply : function(){
50895 return this.applyTemplate.apply(this, arguments);
50898 compile : function(){return this;}
50901 Roo.XTemplate.from = function(el){
50902 el = Roo.getDom(el);
50903 return new Roo.XTemplate(el.value || el.innerHTML);
50905 * Original code for Roojs - LGPL
50906 * <script type="text/javascript">
50910 * @class Roo.XComponent
50911 * A delayed Element creator...
50913 * Mypart.xyx = new Roo.XComponent({
50915 parent : 'Mypart.xyz', // empty == document.element.!!
50919 disabled : function() {}
50921 tree : function() { // return an tree of xtype declared components
50925 xtype : 'NestedLayoutPanel',
50930 * @extends Roo.util.Observable
50932 * @param cfg {Object} configuration of component
50935 Roo.XComponent = function(cfg) {
50936 Roo.apply(this, cfg);
50940 * Fires when this the componnt is built
50941 * @param {Roo.XComponent} c the component
50945 * @event buildcomplete
50946 * Fires on the top level element when all elements have been built
50947 * @param {Roo.XComponent} c the top level component.
50949 'buildcomplete' : true
50953 Roo.XComponent.register(this);
50954 this.modules = false;
50955 this.el = false; // where the layout goes..
50959 Roo.extend(Roo.XComponent, Roo.util.Observable, {
50962 * The created element (with Roo.factory())
50963 * @type {Roo.Layout}
50969 * for BC - use el in new code
50970 * @type {Roo.Layout}
50976 * for BC - use el in new code
50977 * @type {Roo.Layout}
50982 * @cfg {Function|boolean} disabled
50983 * If this module is disabled by some rule, return true from the funtion
50988 * @cfg {String} parent
50989 * Name of parent element which it get xtype added to..
50994 * @cfg {String} order
50995 * Used to set the order in which elements are created (usefull for multiple tabs)
51000 * @cfg {String} name
51001 * String to display while loading.
51005 * @cfg {Array} items
51006 * A single item array - the first element is the root of the tree..
51007 * It's done this way to stay compatible with the Xtype system...
51015 Roo.apply(Roo.XComponent, {
51018 * @property buildCompleted
51019 * True when the builder has completed building the interface.
51022 buildCompleted : false,
51025 * @property topModule
51026 * the upper most module - uses document.element as it's constructor.
51033 * @property modules
51034 * array of modules to be created by registration system.
51035 * @type Roo.XComponent
51042 * Register components to be built later.
51044 * This solves the following issues
51045 * - Building is not done on page load, but after an authentication process has occured.
51046 * - Interface elements are registered on page load
51047 * - Parent Interface elements may not be loaded before child, so this handles that..
51054 module : 'Pman.Tab.projectMgr',
51056 parent : 'Pman.layout',
51057 disabled : false, // or use a function..
51060 * * @param {Object} details about module
51062 register : function(obj) {
51063 this.modules.push(obj);
51067 * convert a string to an object..
51071 toObject : function(str)
51073 if (!str || typeof(str) == 'object') {
51076 var ar = str.split('.');
51080 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51082 throw "Module not found : " + str;
51084 Roo.each(ar, function(e) {
51085 if (typeof(o[e]) == 'undefined') {
51086 throw "Module not found : " + str;
51096 * move modules into their correct place in the tree..
51099 preBuild : function ()
51102 Roo.each(this.modules , function (obj)
51104 obj.parent = this.toObject(obj.parent);
51107 this.topModule = obj;
51111 if (!obj.parent.modules) {
51112 obj.parent.modules = new Roo.util.MixedCollection(false,
51113 function(o) { return o.order + '' }
51117 obj.parent.modules.add(obj);
51122 * make a list of modules to build.
51123 * @return {Array} list of modules.
51126 buildOrder : function()
51129 var cmp = function(a,b) {
51130 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51133 if (!this.topModule || !this.topModule.modules) {
51134 throw "No top level modules to build";
51137 // make a flat list in order of modules to build.
51138 var mods = [ this.topModule ];
51141 // add modules to their parents..
51142 var addMod = function(m) {
51143 // Roo.debug && Roo.log(m.modKey);
51147 m.modules.keySort('ASC', cmp );
51148 m.modules.each(addMod);
51150 // not sure if this is used any more..
51152 m.finalize.name = m.name + " (clean up) ";
51153 mods.push(m.finalize);
51157 this.topModule.modules.keySort('ASC', cmp );
51158 this.topModule.modules.each(addMod);
51163 * Build the registered modules.
51164 * @param {Object} parent element.
51165 * @param {Function} optional method to call after module has been added.
51173 var mods = this.buildOrder();
51175 //this.allmods = mods;
51176 //Roo.debug && Roo.log(mods);
51178 if (!mods.length) { // should not happen
51179 throw "NO modules!!!";
51184 // flash it up as modal - so we store the mask!?
51185 Roo.MessageBox.show({ title: 'loading' });
51186 Roo.MessageBox.show({
51187 title: "Please wait...",
51188 msg: "Building Interface...",
51195 var total = mods.length;
51198 var progressRun = function() {
51199 if (!mods.length) {
51200 Roo.debug && Roo.log('hide?');
51201 Roo.MessageBox.hide();
51202 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51206 var m = mods.shift();
51207 Roo.debug && Roo.log(m);
51208 if (typeof(m) == 'function') { // not sure if this is supported any more..
51210 return progressRun.defer(10, _this);
51213 Roo.MessageBox.updateProgress(
51214 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51216 (m.name ? (' - ' + m.name) : '')
51221 var disabled = (typeof(m.disabled) == 'function') ?
51222 m.disabled.call(m.module.disabled) : m.disabled;
51226 return progressRun(); // we do not update the display!
51230 // it's a top level one..
51231 var layoutbase = new Ext.BorderLayout(document.body, {
51237 tabPosition: 'top',
51238 //resizeTabs: true,
51239 alwaysShowTabs: true,
51243 var tree = m.tree();
51244 tree.region = 'center';
51245 m.el = layoutbase.addxtype(tree);
51247 m.layout = m.panel.layout;
51248 return progressRun.defer(10, _this);
51251 var tree = m.tree();
51252 tree.region = tree.region || m.region;
51253 m.el = m.parent.el.addxtype(tree);
51254 m.fireEvent('built', m);
51256 m.layout = m.panel.layout;
51257 progressRun.defer(10, _this);
51260 progressRun.defer(1, _this);
51270 //<script type="text/javascript">
51275 * @extends Roo.LayoutDialog
51276 * A generic Login Dialog..... - only one needed in theory!?!?
51278 * Fires XComponent builder on success...
51281 * username,password, lang = for login actions.
51282 * check = 1 for periodic checking that sesion is valid.
51283 * passwordRequest = email request password
51284 * logout = 1 = to logout
51286 * Affects: (this id="????" elements)
51287 * loading (removed) (used to indicate application is loading)
51288 * loading-mask (hides) (used to hide application when it's building loading)
51294 * Myapp.login = Roo.Login({
51310 Roo.Login = function(cfg)
51316 Roo.apply(this,cfg);
51318 Roo.onReady(function() {
51324 Roo.Login.superclass.constructor.call(this, this);
51325 //this.addxtype(this.items[0]);
51331 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51334 * @cfg {String} method
51335 * Method used to query for login details.
51340 * @cfg {String} url
51341 * URL to query login data. - eg. baseURL + '/Login.php'
51347 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51352 * @property checkFails
51353 * Number of times we have attempted to get authentication check, and failed.
51358 * @property intervalID
51359 * The window interval that does the constant login checking.
51365 onLoad : function() // called on page load...
51369 if (Roo.get('loading')) { // clear any loading indicator..
51370 Roo.get('loading').remove();
51373 //this.switchLang('en'); // set the language to english..
51376 success: function(response, opts) { // check successfull...
51378 var res = this.processResponse(response);
51379 this.checkFails =0;
51380 if (!res.success) { // error!
51381 this.checkFails = 5;
51382 //console.log('call failure');
51383 return this.failure(response,opts);
51386 if (!res.data.id) { // id=0 == login failure.
51387 return this.show();
51391 //console.log(success);
51392 this.fillAuth(res.data);
51393 this.checkFails =0;
51394 Roo.XComponent.build();
51396 failure : this.show
51402 check: function(cfg) // called every so often to refresh cookie etc..
51404 if (cfg.again) { // could be undefined..
51407 this.checkFails = 0;
51410 if (this.sending) {
51411 if ( this.checkFails > 4) {
51412 Roo.MessageBox.alert("Error",
51413 "Error getting authentication status. - try reloading, or wait a while", function() {
51414 _this.sending = false;
51419 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51422 this.sending = true;
51429 method: this.method,
51430 success: cfg.success || this.success,
51431 failure : cfg.failure || this.failure,
51441 window.onbeforeunload = function() { }; // false does not work for IE..
51451 failure : function() {
51452 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51453 document.location = document.location.toString() + '?ts=' + Math.random();
51457 success : function() {
51458 _this.user = false;
51459 this.checkFails =0;
51461 document.location = document.location.toString() + '?ts=' + Math.random();
51468 processResponse : function (response)
51472 res = Roo.decode(response.responseText);
51474 if (typeof(res) != 'object') {
51475 res = { success : false, errorMsg : res, errors : true };
51477 if (typeof(res.success) == 'undefined') {
51478 res.success = false;
51482 res = { success : false, errorMsg : response.responseText, errors : true };
51487 success : function(response, opts) // check successfull...
51489 this.sending = false;
51490 var res = this.processResponse(response);
51491 if (!res.success) {
51492 return this.failure(response, opts);
51494 if (!res.data || !res.data.id) {
51495 return this.failure(response,opts);
51497 //console.log(res);
51498 this.fillAuth(res.data);
51500 this.checkFails =0;
51505 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51507 this.authUser = -1;
51508 this.sending = false;
51509 var res = this.processResponse(response);
51510 //console.log(res);
51511 if ( this.checkFails > 2) {
51513 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51514 "Error getting authentication status. - try reloading");
51517 opts.callCfg.again = true;
51518 this.check.defer(1000, this, [ opts.callCfg ]);
51524 fillAuth: function(au) {
51525 this.startAuthCheck();
51526 this.authUserId = au.id;
51527 this.authUser = au;
51528 this.lastChecked = new Date();
51529 this.fireEvent('refreshed', au);
51530 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
51531 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
51532 au.lang = au.lang || 'en';
51533 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
51534 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
51535 this.switchLang(au.lang );
51538 // open system... - -on setyp..
51539 if (this.authUserId < 0) {
51540 Roo.MessageBox.alert("Warning",
51541 "This is an open system - please set up a admin user with a password.");
51544 //Pman.onload(); // which should do nothing if it's a re-auth result...
51549 startAuthCheck : function() // starter for timeout checking..
51551 if (this.intervalID) { // timer already in place...
51555 this.intervalID = window.setInterval(function() {
51556 _this.check(false);
51557 }, 120000); // every 120 secs = 2mins..
51563 switchLang : function (lang)
51565 _T = typeof(_T) == 'undefined' ? false : _T;
51566 if (!_T || !lang.length) {
51570 if (!_T && lang != 'en') {
51571 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51575 if (typeof(_T.en) == 'undefined') {
51577 Roo.apply(_T.en, _T);
51580 if (typeof(_T[lang]) == 'undefined') {
51581 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51586 Roo.apply(_T, _T[lang]);
51587 // just need to set the text values for everything...
51589 /* this will not work ...
51593 function formLabel(name, val) {
51594 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
51597 formLabel('password', "Password"+':');
51598 formLabel('username', "Email Address"+':');
51599 formLabel('lang', "Language"+':');
51600 this.dialog.setTitle("Login");
51601 this.dialog.buttons[0].setText("Forgot Password");
51602 this.dialog.buttons[1].setText("Login");
51621 collapsible: false,
51623 center: { // needed??
51626 // tabPosition: 'top',
51629 alwaysShowTabs: false
51633 show : function(dlg)
51635 //console.log(this);
51636 this.form = this.layout.getRegion('center').activePanel.form;
51637 this.form.dialog = dlg;
51638 this.buttons[0].form = this.form;
51639 this.buttons[0].dialog = dlg;
51640 this.buttons[1].form = this.form;
51641 this.buttons[1].dialog = dlg;
51643 //this.resizeToLogo.defer(1000,this);
51644 // this is all related to resizing for logos..
51645 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
51647 // this.resizeToLogo.defer(1000,this);
51650 //var w = Ext.lib.Dom.getViewWidth() - 100;
51651 //var h = Ext.lib.Dom.getViewHeight() - 100;
51652 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
51654 if (this.disabled) {
51659 if (this.user.id < 0) { // used for inital setup situations.
51663 if (this.intervalID) {
51664 // remove the timer
51665 window.clearInterval(this.intervalID);
51666 this.intervalID = false;
51670 if (Roo.get('loading')) {
51671 Roo.get('loading').remove();
51673 if (Roo.get('loading-mask')) {
51674 Roo.get('loading-mask').hide();
51677 //incomming._node = tnode;
51679 //this.dialog.modal = !modal;
51680 //this.dialog.show();
51684 this.form.setValues({
51685 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
51686 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
51689 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
51690 if (this.form.findField('username').getValue().length > 0 ){
51691 this.form.findField('password').focus();
51693 this.form.findField('username').focus();
51701 xtype : 'ContentPanel',
51713 style : 'margin: 10px;',
51716 actionfailed : function(f, act) {
51717 // form can return { errors: .... }
51719 //act.result.errors // invalid form element list...
51720 //act.result.errorMsg// invalid form element list...
51722 this.dialog.el.unmask();
51723 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
51724 "Login failed - communication error - try again.");
51727 actioncomplete: function(re, act) {
51729 Roo.state.Manager.set(
51730 this.dialog.realm + '.username',
51731 this.findField('username').getValue()
51733 Roo.state.Manager.set(
51734 this.dialog.realm + '.lang',
51735 this.findField('lang').getValue()
51738 this.dialog.fillAuth(act.result.data);
51740 this.dialog.hide();
51742 if (Roo.get('loading-mask')) {
51743 Roo.get('loading-mask').show();
51745 Roo.XComponent.build();
51753 xtype : 'TextField',
51755 fieldLabel: "Email Address",
51758 autoCreate : {tag: "input", type: "text", size: "20"}
51761 xtype : 'TextField',
51763 fieldLabel: "Password",
51764 inputType: 'password',
51767 autoCreate : {tag: "input", type: "text", size: "20"},
51769 specialkey : function(e,ev) {
51770 if (ev.keyCode == 13) {
51771 this.form.dialog.el.mask("Logging in");
51772 this.form.doAction('submit', {
51773 url: this.form.dialog.url,
51774 method: this.form.dialog.method
51781 xtype : 'ComboBox',
51783 fieldLabel: "Language",
51786 xtype : 'SimpleStore',
51787 fields: ['lang', 'ldisp'],
51789 [ 'en', 'English' ],
51790 [ 'zh_HK' , '\u7E41\u4E2D' ],
51791 [ 'zh_CN', '\u7C21\u4E2D' ]
51795 valueField : 'lang',
51796 hiddenName: 'lang',
51798 displayField:'ldisp',
51802 triggerAction: 'all',
51803 emptyText:'Select a Language...',
51804 selectOnFocus:true,
51806 select : function(cb, rec, ix) {
51807 this.form.switchLang(rec.data.lang);
51823 text : "Forgot Password",
51825 click : function() {
51826 //console.log(this);
51827 var n = this.form.findField('username').getValue();
51829 Roo.MessageBox.alert("Error", "Fill in your email address");
51833 url: this.dialog.url,
51837 method: this.dialog.method,
51838 success: function(response, opts) { // check successfull...
51840 var res = this.dialog.processResponse(response);
51841 if (!res.success) { // error!
51842 Roo.MessageBox.alert("Error" ,
51843 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
51846 Roo.MessageBox.alert("Notice" ,
51847 "Please check you email for the Password Reset message");
51849 failure : function() {
51850 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
51863 click : function () {
51865 this.dialog.el.mask("Logging in");
51866 this.form.doAction('submit', {
51867 url: this.dialog.url,
51868 method: this.dialog.method