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 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
29682 //config.autoCreate = true;
29686 config.autoTabs = false;
29687 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29688 this.body.setStyle({overflow:"hidden", position:"relative"});
29689 this.layout = new Roo.BorderLayout(this.body.dom, config);
29690 this.layout.monitorWindowResize = false;
29691 this.el.addClass("x-dlg-auto-layout");
29692 // fix case when center region overwrites center function
29693 this.center = Roo.BasicDialog.prototype.center;
29694 this.on("show", this.layout.layout, this.layout, true);
29695 if (config.items) {
29696 var xitems = config.items;
29697 delete config.items;
29698 Roo.each(xitems, this.addxtype, this);
29703 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29705 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29708 endUpdate : function(){
29709 this.layout.endUpdate();
29713 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29716 beginUpdate : function(){
29717 this.layout.beginUpdate();
29721 * Get the BorderLayout for this dialog
29722 * @return {Roo.BorderLayout}
29724 getLayout : function(){
29725 return this.layout;
29728 showEl : function(){
29729 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29731 this.layout.layout();
29736 // Use the syncHeightBeforeShow config option to control this automatically
29737 syncBodyHeight : function(){
29738 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29739 if(this.layout){this.layout.layout();}
29743 * Add an xtype element (actually adds to the layout.)
29744 * @return {Object} xdata xtype object data.
29747 addxtype : function(c) {
29748 return this.layout.addxtype(c);
29752 * Ext JS Library 1.1.1
29753 * Copyright(c) 2006-2007, Ext JS, LLC.
29755 * Originally Released Under LGPL - original licence link has changed is not relivant.
29758 * <script type="text/javascript">
29762 * @class Roo.MessageBox
29763 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29767 Roo.Msg.alert('Status', 'Changes saved successfully.');
29769 // Prompt for user data:
29770 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29772 // process text value...
29776 // Show a dialog using config options:
29778 title:'Save Changes?',
29779 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29780 buttons: Roo.Msg.YESNOCANCEL,
29787 Roo.MessageBox = function(){
29788 var dlg, opt, mask, waitTimer;
29789 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29790 var buttons, activeTextEl, bwidth;
29793 var handleButton = function(button){
29795 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29799 var handleHide = function(){
29800 if(opt && opt.cls){
29801 dlg.el.removeClass(opt.cls);
29804 Roo.TaskMgr.stop(waitTimer);
29810 var updateButtons = function(b){
29813 buttons["ok"].hide();
29814 buttons["cancel"].hide();
29815 buttons["yes"].hide();
29816 buttons["no"].hide();
29817 dlg.footer.dom.style.display = 'none';
29820 dlg.footer.dom.style.display = '';
29821 for(var k in buttons){
29822 if(typeof buttons[k] != "function"){
29825 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29826 width += buttons[k].el.getWidth()+15;
29836 var handleEsc = function(d, k, e){
29837 if(opt && opt.closable !== false){
29847 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29848 * @return {Roo.BasicDialog} The BasicDialog element
29850 getDialog : function(){
29852 dlg = new Roo.BasicDialog("x-msg-box", {
29857 constraintoviewport:false,
29859 collapsible : false,
29862 width:400, height:100,
29863 buttonAlign:"center",
29864 closeClick : function(){
29865 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29866 handleButton("no");
29868 handleButton("cancel");
29872 dlg.on("hide", handleHide);
29874 dlg.addKeyListener(27, handleEsc);
29876 var bt = this.buttonText;
29877 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29878 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29879 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29880 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29881 bodyEl = dlg.body.createChild({
29883 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>'
29885 msgEl = bodyEl.dom.firstChild;
29886 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29887 textboxEl.enableDisplayMode();
29888 textboxEl.addKeyListener([10,13], function(){
29889 if(dlg.isVisible() && opt && opt.buttons){
29890 if(opt.buttons.ok){
29891 handleButton("ok");
29892 }else if(opt.buttons.yes){
29893 handleButton("yes");
29897 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29898 textareaEl.enableDisplayMode();
29899 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29900 progressEl.enableDisplayMode();
29901 var pf = progressEl.dom.firstChild;
29903 pp = Roo.get(pf.firstChild);
29904 pp.setHeight(pf.offsetHeight);
29912 * Updates the message box body text
29913 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29914 * the XHTML-compliant non-breaking space character '&#160;')
29915 * @return {Roo.MessageBox} This message box
29917 updateText : function(text){
29918 if(!dlg.isVisible() && !opt.width){
29919 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29921 msgEl.innerHTML = text || ' ';
29922 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29923 Math.max(opt.minWidth || this.minWidth, bwidth));
29925 activeTextEl.setWidth(w);
29927 if(dlg.isVisible()){
29928 dlg.fixedcenter = false;
29930 dlg.setContentSize(w, bodyEl.getHeight());
29931 if(dlg.isVisible()){
29932 dlg.fixedcenter = true;
29938 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29939 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29940 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29941 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29942 * @return {Roo.MessageBox} This message box
29944 updateProgress : function(value, text){
29946 this.updateText(text);
29948 if (pp) { // weird bug on my firefox - for some reason this is not defined
29949 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29955 * Returns true if the message box is currently displayed
29956 * @return {Boolean} True if the message box is visible, else false
29958 isVisible : function(){
29959 return dlg && dlg.isVisible();
29963 * Hides the message box if it is displayed
29966 if(this.isVisible()){
29972 * Displays a new message box, or reinitializes an existing message box, based on the config options
29973 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29974 * The following config object properties are supported:
29976 Property Type Description
29977 ---------- --------------- ------------------------------------------------------------------------------------
29978 animEl String/Element An id or Element from which the message box should animate as it opens and
29979 closes (defaults to undefined)
29980 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29981 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29982 closable Boolean False to hide the top-right close button (defaults to true). Note that
29983 progress and wait dialogs will ignore this property and always hide the
29984 close button as they can only be closed programmatically.
29985 cls String A custom CSS class to apply to the message box element
29986 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29987 displayed (defaults to 75)
29988 fn Function A callback function to execute after closing the dialog. The arguments to the
29989 function will be btn (the name of the button that was clicked, if applicable,
29990 e.g. "ok"), and text (the value of the active text field, if applicable).
29991 Progress and wait dialogs will ignore this option since they do not respond to
29992 user actions and can only be closed programmatically, so any required function
29993 should be called by the same code after it closes the dialog.
29994 icon String A CSS class that provides a background image to be used as an icon for
29995 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29996 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29997 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29998 modal Boolean False to allow user interaction with the page while the message box is
29999 displayed (defaults to true)
30000 msg String A string that will replace the existing message box body text (defaults
30001 to the XHTML-compliant non-breaking space character ' ')
30002 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30003 progress Boolean True to display a progress bar (defaults to false)
30004 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30005 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30006 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30007 title String The title text
30008 value String The string value to set into the active textbox element if displayed
30009 wait Boolean True to display a progress bar (defaults to false)
30010 width Number The width of the dialog in pixels
30017 msg: 'Please enter your address:',
30019 buttons: Roo.MessageBox.OKCANCEL,
30022 animEl: 'addAddressBtn'
30025 * @param {Object} config Configuration options
30026 * @return {Roo.MessageBox} This message box
30028 show : function(options){
30029 if(this.isVisible()){
30032 var d = this.getDialog();
30034 d.setTitle(opt.title || " ");
30035 d.close.setDisplayed(opt.closable !== false);
30036 activeTextEl = textboxEl;
30037 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30042 textareaEl.setHeight(typeof opt.multiline == "number" ?
30043 opt.multiline : this.defaultTextHeight);
30044 activeTextEl = textareaEl;
30053 progressEl.setDisplayed(opt.progress === true);
30054 this.updateProgress(0);
30055 activeTextEl.dom.value = opt.value || "";
30057 dlg.setDefaultButton(activeTextEl);
30059 var bs = opt.buttons;
30062 db = buttons["ok"];
30063 }else if(bs && bs.yes){
30064 db = buttons["yes"];
30066 dlg.setDefaultButton(db);
30068 bwidth = updateButtons(opt.buttons);
30069 this.updateText(opt.msg);
30071 d.el.addClass(opt.cls);
30073 d.proxyDrag = opt.proxyDrag === true;
30074 d.modal = opt.modal !== false;
30075 d.mask = opt.modal !== false ? mask : false;
30076 if(!d.isVisible()){
30077 // force it to the end of the z-index stack so it gets a cursor in FF
30078 document.body.appendChild(dlg.el.dom);
30079 d.animateTarget = null;
30080 d.show(options.animEl);
30086 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30087 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30088 * and closing the message box when the process is complete.
30089 * @param {String} title The title bar text
30090 * @param {String} msg The message box body text
30091 * @return {Roo.MessageBox} This message box
30093 progress : function(title, msg){
30100 minWidth: this.minProgressWidth,
30107 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30108 * If a callback function is passed it will be called after the user clicks the button, and the
30109 * id of the button that was clicked will be passed as the only parameter to the callback
30110 * (could also be the top-right close button).
30111 * @param {String} title The title bar text
30112 * @param {String} msg The message box body text
30113 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30114 * @param {Object} scope (optional) The scope of the callback function
30115 * @return {Roo.MessageBox} This message box
30117 alert : function(title, msg, fn, scope){
30130 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30131 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30132 * You are responsible for closing the message box when the process is complete.
30133 * @param {String} msg The message box body text
30134 * @param {String} title (optional) The title bar text
30135 * @return {Roo.MessageBox} This message box
30137 wait : function(msg, title){
30148 waitTimer = Roo.TaskMgr.start({
30150 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30158 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30159 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30160 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30161 * @param {String} title The title bar text
30162 * @param {String} msg The message box body text
30163 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30164 * @param {Object} scope (optional) The scope of the callback function
30165 * @return {Roo.MessageBox} This message box
30167 confirm : function(title, msg, fn, scope){
30171 buttons: this.YESNO,
30180 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30181 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30182 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30183 * (could also be the top-right close button) and the text that was entered will be passed as the two
30184 * parameters to the callback.
30185 * @param {String} title The title bar text
30186 * @param {String} msg The message box body text
30187 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30188 * @param {Object} scope (optional) The scope of the callback function
30189 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30190 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30191 * @return {Roo.MessageBox} This message box
30193 prompt : function(title, msg, fn, scope, multiline){
30197 buttons: this.OKCANCEL,
30202 multiline: multiline,
30209 * Button config that displays a single OK button
30214 * Button config that displays Yes and No buttons
30217 YESNO : {yes:true, no:true},
30219 * Button config that displays OK and Cancel buttons
30222 OKCANCEL : {ok:true, cancel:true},
30224 * Button config that displays Yes, No and Cancel buttons
30227 YESNOCANCEL : {yes:true, no:true, cancel:true},
30230 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30233 defaultTextHeight : 75,
30235 * The maximum width in pixels of the message box (defaults to 600)
30240 * The minimum width in pixels of the message box (defaults to 100)
30245 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30246 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30249 minProgressWidth : 250,
30251 * An object containing the default button text strings that can be overriden for localized language support.
30252 * Supported properties are: ok, cancel, yes and no.
30253 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30266 * Shorthand for {@link Roo.MessageBox}
30268 Roo.Msg = Roo.MessageBox;/*
30270 * Ext JS Library 1.1.1
30271 * Copyright(c) 2006-2007, Ext JS, LLC.
30273 * Originally Released Under LGPL - original licence link has changed is not relivant.
30276 * <script type="text/javascript">
30279 * @class Roo.QuickTips
30280 * Provides attractive and customizable tooltips for any element.
30283 Roo.QuickTips = function(){
30284 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30285 var ce, bd, xy, dd;
30286 var visible = false, disabled = true, inited = false;
30287 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30289 var onOver = function(e){
30293 var t = e.getTarget();
30294 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30297 if(ce && t == ce.el){
30298 clearTimeout(hideProc);
30301 if(t && tagEls[t.id]){
30302 tagEls[t.id].el = t;
30303 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30306 var ttp, et = Roo.fly(t);
30307 var ns = cfg.namespace;
30308 if(tm.interceptTitles && t.title){
30311 t.removeAttribute("title");
30312 e.preventDefault();
30314 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30317 showProc = show.defer(tm.showDelay, tm, [{
30320 width: et.getAttributeNS(ns, cfg.width),
30321 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30322 title: et.getAttributeNS(ns, cfg.title),
30323 cls: et.getAttributeNS(ns, cfg.cls)
30328 var onOut = function(e){
30329 clearTimeout(showProc);
30330 var t = e.getTarget();
30331 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30332 hideProc = setTimeout(hide, tm.hideDelay);
30336 var onMove = function(e){
30342 if(tm.trackMouse && ce){
30347 var onDown = function(e){
30348 clearTimeout(showProc);
30349 clearTimeout(hideProc);
30351 if(tm.hideOnClick){
30354 tm.enable.defer(100, tm);
30359 var getPad = function(){
30360 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30363 var show = function(o){
30367 clearTimeout(dismissProc);
30369 if(removeCls){ // in case manually hidden
30370 el.removeClass(removeCls);
30374 el.addClass(ce.cls);
30375 removeCls = ce.cls;
30378 tipTitle.update(ce.title);
30381 tipTitle.update('');
30384 el.dom.style.width = tm.maxWidth+'px';
30385 //tipBody.dom.style.width = '';
30386 tipBodyText.update(o.text);
30387 var p = getPad(), w = ce.width;
30389 var td = tipBodyText.dom;
30390 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30391 if(aw > tm.maxWidth){
30393 }else if(aw < tm.minWidth){
30399 //tipBody.setWidth(w);
30400 el.setWidth(parseInt(w, 10) + p);
30401 if(ce.autoHide === false){
30402 close.setDisplayed(true);
30407 close.setDisplayed(false);
30413 el.avoidY = xy[1]-18;
30418 el.setStyle("visibility", "visible");
30419 el.fadeIn({callback: afterShow});
30425 var afterShow = function(){
30429 if(tm.autoDismiss && ce.autoHide !== false){
30430 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30435 var hide = function(noanim){
30436 clearTimeout(dismissProc);
30437 clearTimeout(hideProc);
30439 if(el.isVisible()){
30441 if(noanim !== true && tm.animate){
30442 el.fadeOut({callback: afterHide});
30449 var afterHide = function(){
30452 el.removeClass(removeCls);
30459 * @cfg {Number} minWidth
30460 * The minimum width of the quick tip (defaults to 40)
30464 * @cfg {Number} maxWidth
30465 * The maximum width of the quick tip (defaults to 300)
30469 * @cfg {Boolean} interceptTitles
30470 * True to automatically use the element's DOM title value if available (defaults to false)
30472 interceptTitles : false,
30474 * @cfg {Boolean} trackMouse
30475 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30477 trackMouse : false,
30479 * @cfg {Boolean} hideOnClick
30480 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30482 hideOnClick : true,
30484 * @cfg {Number} showDelay
30485 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30489 * @cfg {Number} hideDelay
30490 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30494 * @cfg {Boolean} autoHide
30495 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30496 * Used in conjunction with hideDelay.
30501 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30502 * (defaults to true). Used in conjunction with autoDismissDelay.
30504 autoDismiss : true,
30507 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30509 autoDismissDelay : 5000,
30511 * @cfg {Boolean} animate
30512 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30517 * @cfg {String} title
30518 * Title text to display (defaults to ''). This can be any valid HTML markup.
30522 * @cfg {String} text
30523 * Body text to display (defaults to ''). This can be any valid HTML markup.
30527 * @cfg {String} cls
30528 * A CSS class to apply to the base quick tip element (defaults to '').
30532 * @cfg {Number} width
30533 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30534 * minWidth or maxWidth.
30539 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30540 * or display QuickTips in a page.
30543 tm = Roo.QuickTips;
30544 cfg = tm.tagConfig;
30546 if(!Roo.isReady){ // allow calling of init() before onReady
30547 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30550 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30551 el.fxDefaults = {stopFx: true};
30552 // maximum custom styling
30553 //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>');
30554 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>');
30555 tipTitle = el.child('h3');
30556 tipTitle.enableDisplayMode("block");
30557 tipBody = el.child('div.x-tip-bd');
30558 tipBodyText = el.child('div.x-tip-bd-inner');
30559 //bdLeft = el.child('div.x-tip-bd-left');
30560 //bdRight = el.child('div.x-tip-bd-right');
30561 close = el.child('div.x-tip-close');
30562 close.enableDisplayMode("block");
30563 close.on("click", hide);
30564 var d = Roo.get(document);
30565 d.on("mousedown", onDown);
30566 d.on("mouseover", onOver);
30567 d.on("mouseout", onOut);
30568 d.on("mousemove", onMove);
30569 esc = d.addKeyListener(27, hide);
30572 dd = el.initDD("default", null, {
30573 onDrag : function(){
30577 dd.setHandleElId(tipTitle.id);
30586 * Configures a new quick tip instance and assigns it to a target element. The following config options
30589 Property Type Description
30590 ---------- --------------------- ------------------------------------------------------------------------
30591 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30593 * @param {Object} config The config object
30595 register : function(config){
30596 var cs = config instanceof Array ? config : arguments;
30597 for(var i = 0, len = cs.length; i < len; i++) {
30599 var target = c.target;
30601 if(target instanceof Array){
30602 for(var j = 0, jlen = target.length; j < jlen; j++){
30603 tagEls[target[j]] = c;
30606 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30613 * Removes this quick tip from its element and destroys it.
30614 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30616 unregister : function(el){
30617 delete tagEls[Roo.id(el)];
30621 * Enable this quick tip.
30623 enable : function(){
30624 if(inited && disabled){
30626 if(locks.length < 1){
30633 * Disable this quick tip.
30635 disable : function(){
30637 clearTimeout(showProc);
30638 clearTimeout(hideProc);
30639 clearTimeout(dismissProc);
30647 * Returns true if the quick tip is enabled, else false.
30649 isEnabled : function(){
30656 attribute : "qtip",
30666 // backwards compat
30667 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30669 * Ext JS Library 1.1.1
30670 * Copyright(c) 2006-2007, Ext JS, LLC.
30672 * Originally Released Under LGPL - original licence link has changed is not relivant.
30675 * <script type="text/javascript">
30680 * @class Roo.tree.TreePanel
30681 * @extends Roo.data.Tree
30683 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30684 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30685 * @cfg {Boolean} enableDD true to enable drag and drop
30686 * @cfg {Boolean} enableDrag true to enable just drag
30687 * @cfg {Boolean} enableDrop true to enable just drop
30688 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30689 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30690 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30691 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30692 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30693 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30694 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30695 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30696 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30697 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30698 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30699 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30700 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30701 * @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>
30702 * @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>
30705 * @param {String/HTMLElement/Element} el The container element
30706 * @param {Object} config
30708 Roo.tree.TreePanel = function(el, config){
30710 var loader = false;
30712 root = config.root;
30713 delete config.root;
30715 if (config.loader) {
30716 loader = config.loader;
30717 delete config.loader;
30720 Roo.apply(this, config);
30721 Roo.tree.TreePanel.superclass.constructor.call(this);
30722 this.el = Roo.get(el);
30723 this.el.addClass('x-tree');
30724 //console.log(root);
30726 this.setRootNode( Roo.factory(root, Roo.tree));
30729 this.loader = Roo.factory(loader, Roo.tree);
30732 * Read-only. The id of the container element becomes this TreePanel's id.
30734 this.id = this.el.id;
30737 * @event beforeload
30738 * Fires before a node is loaded, return false to cancel
30739 * @param {Node} node The node being loaded
30741 "beforeload" : true,
30744 * Fires when a node is loaded
30745 * @param {Node} node The node that was loaded
30749 * @event textchange
30750 * Fires when the text for a node is changed
30751 * @param {Node} node The node
30752 * @param {String} text The new text
30753 * @param {String} oldText The old text
30755 "textchange" : true,
30757 * @event beforeexpand
30758 * Fires before a node is expanded, return false to cancel.
30759 * @param {Node} node The node
30760 * @param {Boolean} deep
30761 * @param {Boolean} anim
30763 "beforeexpand" : true,
30765 * @event beforecollapse
30766 * Fires before a node is collapsed, return false to cancel.
30767 * @param {Node} node The node
30768 * @param {Boolean} deep
30769 * @param {Boolean} anim
30771 "beforecollapse" : true,
30774 * Fires when a node is expanded
30775 * @param {Node} node The node
30779 * @event disabledchange
30780 * Fires when the disabled status of a node changes
30781 * @param {Node} node The node
30782 * @param {Boolean} disabled
30784 "disabledchange" : true,
30787 * Fires when a node is collapsed
30788 * @param {Node} node The node
30792 * @event beforeclick
30793 * Fires before click processing on a node. Return false to cancel the default action.
30794 * @param {Node} node The node
30795 * @param {Roo.EventObject} e The event object
30797 "beforeclick":true,
30799 * @event checkchange
30800 * Fires when a node with a checkbox's checked property changes
30801 * @param {Node} this This node
30802 * @param {Boolean} checked
30804 "checkchange":true,
30807 * Fires when a node is clicked
30808 * @param {Node} node The node
30809 * @param {Roo.EventObject} e The event object
30814 * Fires when a node is double clicked
30815 * @param {Node} node The node
30816 * @param {Roo.EventObject} e The event object
30820 * @event contextmenu
30821 * Fires when a node is right clicked
30822 * @param {Node} node The node
30823 * @param {Roo.EventObject} e The event object
30825 "contextmenu":true,
30827 * @event beforechildrenrendered
30828 * Fires right before the child nodes for a node are rendered
30829 * @param {Node} node The node
30831 "beforechildrenrendered":true,
30834 * Fires when a node starts being dragged
30835 * @param {Roo.tree.TreePanel} this
30836 * @param {Roo.tree.TreeNode} node
30837 * @param {event} e The raw browser event
30839 "startdrag" : true,
30842 * Fires when a drag operation is complete
30843 * @param {Roo.tree.TreePanel} this
30844 * @param {Roo.tree.TreeNode} node
30845 * @param {event} e The raw browser event
30850 * Fires when a dragged node is dropped on a valid DD target
30851 * @param {Roo.tree.TreePanel} this
30852 * @param {Roo.tree.TreeNode} node
30853 * @param {DD} dd The dd it was dropped on
30854 * @param {event} e The raw browser event
30858 * @event beforenodedrop
30859 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30860 * passed to handlers has the following properties:<br />
30861 * <ul style="padding:5px;padding-left:16px;">
30862 * <li>tree - The TreePanel</li>
30863 * <li>target - The node being targeted for the drop</li>
30864 * <li>data - The drag data from the drag source</li>
30865 * <li>point - The point of the drop - append, above or below</li>
30866 * <li>source - The drag source</li>
30867 * <li>rawEvent - Raw mouse event</li>
30868 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30869 * to be inserted by setting them on this object.</li>
30870 * <li>cancel - Set this to true to cancel the drop.</li>
30872 * @param {Object} dropEvent
30874 "beforenodedrop" : true,
30877 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30878 * passed to handlers has the following properties:<br />
30879 * <ul style="padding:5px;padding-left:16px;">
30880 * <li>tree - The TreePanel</li>
30881 * <li>target - The node being targeted for the drop</li>
30882 * <li>data - The drag data from the drag source</li>
30883 * <li>point - The point of the drop - append, above or below</li>
30884 * <li>source - The drag source</li>
30885 * <li>rawEvent - Raw mouse event</li>
30886 * <li>dropNode - Dropped node(s).</li>
30888 * @param {Object} dropEvent
30892 * @event nodedragover
30893 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30894 * passed to handlers has the following properties:<br />
30895 * <ul style="padding:5px;padding-left:16px;">
30896 * <li>tree - The TreePanel</li>
30897 * <li>target - The node being targeted for the drop</li>
30898 * <li>data - The drag data from the drag source</li>
30899 * <li>point - The point of the drop - append, above or below</li>
30900 * <li>source - The drag source</li>
30901 * <li>rawEvent - Raw mouse event</li>
30902 * <li>dropNode - Drop node(s) provided by the source.</li>
30903 * <li>cancel - Set this to true to signal drop not allowed.</li>
30905 * @param {Object} dragOverEvent
30907 "nodedragover" : true
30910 if(this.singleExpand){
30911 this.on("beforeexpand", this.restrictExpand, this);
30914 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30915 rootVisible : true,
30916 animate: Roo.enableFx,
30919 hlDrop : Roo.enableFx,
30923 rendererTip: false,
30925 restrictExpand : function(node){
30926 var p = node.parentNode;
30928 if(p.expandedChild && p.expandedChild.parentNode == p){
30929 p.expandedChild.collapse();
30931 p.expandedChild = node;
30935 // private override
30936 setRootNode : function(node){
30937 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30938 if(!this.rootVisible){
30939 node.ui = new Roo.tree.RootTreeNodeUI(node);
30945 * Returns the container element for this TreePanel
30947 getEl : function(){
30952 * Returns the default TreeLoader for this TreePanel
30954 getLoader : function(){
30955 return this.loader;
30961 expandAll : function(){
30962 this.root.expand(true);
30966 * Collapse all nodes
30968 collapseAll : function(){
30969 this.root.collapse(true);
30973 * Returns the selection model used by this TreePanel
30975 getSelectionModel : function(){
30976 if(!this.selModel){
30977 this.selModel = new Roo.tree.DefaultSelectionModel();
30979 return this.selModel;
30983 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30984 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30985 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30988 getChecked : function(a, startNode){
30989 startNode = startNode || this.root;
30991 var f = function(){
30992 if(this.attributes.checked){
30993 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30996 startNode.cascade(f);
31001 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31002 * @param {String} path
31003 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31004 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31005 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31007 expandPath : function(path, attr, callback){
31008 attr = attr || "id";
31009 var keys = path.split(this.pathSeparator);
31010 var curNode = this.root;
31011 if(curNode.attributes[attr] != keys[1]){ // invalid root
31013 callback(false, null);
31018 var f = function(){
31019 if(++index == keys.length){
31021 callback(true, curNode);
31025 var c = curNode.findChild(attr, keys[index]);
31028 callback(false, curNode);
31033 c.expand(false, false, f);
31035 curNode.expand(false, false, f);
31039 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31040 * @param {String} path
31041 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31042 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31043 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31045 selectPath : function(path, attr, callback){
31046 attr = attr || "id";
31047 var keys = path.split(this.pathSeparator);
31048 var v = keys.pop();
31049 if(keys.length > 0){
31050 var f = function(success, node){
31051 if(success && node){
31052 var n = node.findChild(attr, v);
31058 }else if(callback){
31059 callback(false, n);
31063 callback(false, n);
31067 this.expandPath(keys.join(this.pathSeparator), attr, f);
31069 this.root.select();
31071 callback(true, this.root);
31076 getTreeEl : function(){
31081 * Trigger rendering of this TreePanel
31083 render : function(){
31084 if (this.innerCt) {
31085 return this; // stop it rendering more than once!!
31088 this.innerCt = this.el.createChild({tag:"ul",
31089 cls:"x-tree-root-ct " +
31090 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31092 if(this.containerScroll){
31093 Roo.dd.ScrollManager.register(this.el);
31095 if((this.enableDD || this.enableDrop) && !this.dropZone){
31097 * The dropZone used by this tree if drop is enabled
31098 * @type Roo.tree.TreeDropZone
31100 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31101 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31104 if((this.enableDD || this.enableDrag) && !this.dragZone){
31106 * The dragZone used by this tree if drag is enabled
31107 * @type Roo.tree.TreeDragZone
31109 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31110 ddGroup: this.ddGroup || "TreeDD",
31111 scroll: this.ddScroll
31114 this.getSelectionModel().init(this);
31116 console.log("ROOT not set in tree");
31119 this.root.render();
31120 if(!this.rootVisible){
31121 this.root.renderChildren();
31127 * Ext JS Library 1.1.1
31128 * Copyright(c) 2006-2007, Ext JS, LLC.
31130 * Originally Released Under LGPL - original licence link has changed is not relivant.
31133 * <script type="text/javascript">
31138 * @class Roo.tree.DefaultSelectionModel
31139 * @extends Roo.util.Observable
31140 * The default single selection for a TreePanel.
31142 Roo.tree.DefaultSelectionModel = function(){
31143 this.selNode = null;
31147 * @event selectionchange
31148 * Fires when the selected node changes
31149 * @param {DefaultSelectionModel} this
31150 * @param {TreeNode} node the new selection
31152 "selectionchange" : true,
31155 * @event beforeselect
31156 * Fires before the selected node changes, return false to cancel the change
31157 * @param {DefaultSelectionModel} this
31158 * @param {TreeNode} node the new selection
31159 * @param {TreeNode} node the old selection
31161 "beforeselect" : true
31165 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31166 init : function(tree){
31168 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31169 tree.on("click", this.onNodeClick, this);
31172 onNodeClick : function(node, e){
31173 if (e.ctrlKey && this.selNode == node) {
31174 this.unselect(node);
31182 * @param {TreeNode} node The node to select
31183 * @return {TreeNode} The selected node
31185 select : function(node){
31186 var last = this.selNode;
31187 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31189 last.ui.onSelectedChange(false);
31191 this.selNode = node;
31192 node.ui.onSelectedChange(true);
31193 this.fireEvent("selectionchange", this, node, last);
31200 * @param {TreeNode} node The node to unselect
31202 unselect : function(node){
31203 if(this.selNode == node){
31204 this.clearSelections();
31209 * Clear all selections
31211 clearSelections : function(){
31212 var n = this.selNode;
31214 n.ui.onSelectedChange(false);
31215 this.selNode = null;
31216 this.fireEvent("selectionchange", this, null);
31222 * Get the selected node
31223 * @return {TreeNode} The selected node
31225 getSelectedNode : function(){
31226 return this.selNode;
31230 * Returns true if the node is selected
31231 * @param {TreeNode} node The node to check
31232 * @return {Boolean}
31234 isSelected : function(node){
31235 return this.selNode == node;
31239 * Selects the node above the selected node in the tree, intelligently walking the nodes
31240 * @return TreeNode The new selection
31242 selectPrevious : function(){
31243 var s = this.selNode || this.lastSelNode;
31247 var ps = s.previousSibling;
31249 if(!ps.isExpanded() || ps.childNodes.length < 1){
31250 return this.select(ps);
31252 var lc = ps.lastChild;
31253 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31256 return this.select(lc);
31258 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31259 return this.select(s.parentNode);
31265 * Selects the node above the selected node in the tree, intelligently walking the nodes
31266 * @return TreeNode The new selection
31268 selectNext : function(){
31269 var s = this.selNode || this.lastSelNode;
31273 if(s.firstChild && s.isExpanded()){
31274 return this.select(s.firstChild);
31275 }else if(s.nextSibling){
31276 return this.select(s.nextSibling);
31277 }else if(s.parentNode){
31279 s.parentNode.bubble(function(){
31280 if(this.nextSibling){
31281 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31290 onKeyDown : function(e){
31291 var s = this.selNode || this.lastSelNode;
31292 // undesirable, but required
31297 var k = e.getKey();
31305 this.selectPrevious();
31308 e.preventDefault();
31309 if(s.hasChildNodes()){
31310 if(!s.isExpanded()){
31312 }else if(s.firstChild){
31313 this.select(s.firstChild, e);
31318 e.preventDefault();
31319 if(s.hasChildNodes() && s.isExpanded()){
31321 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31322 this.select(s.parentNode, e);
31330 * @class Roo.tree.MultiSelectionModel
31331 * @extends Roo.util.Observable
31332 * Multi selection for a TreePanel.
31334 Roo.tree.MultiSelectionModel = function(){
31335 this.selNodes = [];
31339 * @event selectionchange
31340 * Fires when the selected nodes change
31341 * @param {MultiSelectionModel} this
31342 * @param {Array} nodes Array of the selected nodes
31344 "selectionchange" : true
31348 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31349 init : function(tree){
31351 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31352 tree.on("click", this.onNodeClick, this);
31355 onNodeClick : function(node, e){
31356 this.select(node, e, e.ctrlKey);
31361 * @param {TreeNode} node The node to select
31362 * @param {EventObject} e (optional) An event associated with the selection
31363 * @param {Boolean} keepExisting True to retain existing selections
31364 * @return {TreeNode} The selected node
31366 select : function(node, e, keepExisting){
31367 if(keepExisting !== true){
31368 this.clearSelections(true);
31370 if(this.isSelected(node)){
31371 this.lastSelNode = node;
31374 this.selNodes.push(node);
31375 this.selMap[node.id] = node;
31376 this.lastSelNode = node;
31377 node.ui.onSelectedChange(true);
31378 this.fireEvent("selectionchange", this, this.selNodes);
31384 * @param {TreeNode} node The node to unselect
31386 unselect : function(node){
31387 if(this.selMap[node.id]){
31388 node.ui.onSelectedChange(false);
31389 var sn = this.selNodes;
31392 index = sn.indexOf(node);
31394 for(var i = 0, len = sn.length; i < len; i++){
31402 this.selNodes.splice(index, 1);
31404 delete this.selMap[node.id];
31405 this.fireEvent("selectionchange", this, this.selNodes);
31410 * Clear all selections
31412 clearSelections : function(suppressEvent){
31413 var sn = this.selNodes;
31415 for(var i = 0, len = sn.length; i < len; i++){
31416 sn[i].ui.onSelectedChange(false);
31418 this.selNodes = [];
31420 if(suppressEvent !== true){
31421 this.fireEvent("selectionchange", this, this.selNodes);
31427 * Returns true if the node is selected
31428 * @param {TreeNode} node The node to check
31429 * @return {Boolean}
31431 isSelected : function(node){
31432 return this.selMap[node.id] ? true : false;
31436 * Returns an array of the selected nodes
31439 getSelectedNodes : function(){
31440 return this.selNodes;
31443 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31445 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31447 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31450 * Ext JS Library 1.1.1
31451 * Copyright(c) 2006-2007, Ext JS, LLC.
31453 * Originally Released Under LGPL - original licence link has changed is not relivant.
31456 * <script type="text/javascript">
31460 * @class Roo.tree.TreeNode
31461 * @extends Roo.data.Node
31462 * @cfg {String} text The text for this node
31463 * @cfg {Boolean} expanded true to start the node expanded
31464 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31465 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31466 * @cfg {Boolean} disabled true to start the node disabled
31467 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31468 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31469 * @cfg {String} cls A css class to be added to the node
31470 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31471 * @cfg {String} href URL of the link used for the node (defaults to #)
31472 * @cfg {String} hrefTarget target frame for the link
31473 * @cfg {String} qtip An Ext QuickTip for the node
31474 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31475 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31476 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31477 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31478 * (defaults to undefined with no checkbox rendered)
31480 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31482 Roo.tree.TreeNode = function(attributes){
31483 attributes = attributes || {};
31484 if(typeof attributes == "string"){
31485 attributes = {text: attributes};
31487 this.childrenRendered = false;
31488 this.rendered = false;
31489 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31490 this.expanded = attributes.expanded === true;
31491 this.isTarget = attributes.isTarget !== false;
31492 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31493 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31496 * Read-only. The text for this node. To change it use setText().
31499 this.text = attributes.text;
31501 * True if this node is disabled.
31504 this.disabled = attributes.disabled === true;
31508 * @event textchange
31509 * Fires when the text for this node is changed
31510 * @param {Node} this This node
31511 * @param {String} text The new text
31512 * @param {String} oldText The old text
31514 "textchange" : true,
31516 * @event beforeexpand
31517 * Fires before this node is expanded, return false to cancel.
31518 * @param {Node} this This node
31519 * @param {Boolean} deep
31520 * @param {Boolean} anim
31522 "beforeexpand" : true,
31524 * @event beforecollapse
31525 * Fires before this node is collapsed, return false to cancel.
31526 * @param {Node} this This node
31527 * @param {Boolean} deep
31528 * @param {Boolean} anim
31530 "beforecollapse" : true,
31533 * Fires when this node is expanded
31534 * @param {Node} this This node
31538 * @event disabledchange
31539 * Fires when the disabled status of this node changes
31540 * @param {Node} this This node
31541 * @param {Boolean} disabled
31543 "disabledchange" : true,
31546 * Fires when this node is collapsed
31547 * @param {Node} this This node
31551 * @event beforeclick
31552 * Fires before click processing. Return false to cancel the default action.
31553 * @param {Node} this This node
31554 * @param {Roo.EventObject} e The event object
31556 "beforeclick":true,
31558 * @event checkchange
31559 * Fires when a node with a checkbox's checked property changes
31560 * @param {Node} this This node
31561 * @param {Boolean} checked
31563 "checkchange":true,
31566 * Fires when this node is clicked
31567 * @param {Node} this This node
31568 * @param {Roo.EventObject} e The event object
31573 * Fires when this node is double clicked
31574 * @param {Node} this This node
31575 * @param {Roo.EventObject} e The event object
31579 * @event contextmenu
31580 * Fires when this node is right clicked
31581 * @param {Node} this This node
31582 * @param {Roo.EventObject} e The event object
31584 "contextmenu":true,
31586 * @event beforechildrenrendered
31587 * Fires right before the child nodes for this node are rendered
31588 * @param {Node} this This node
31590 "beforechildrenrendered":true
31593 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31596 * Read-only. The UI for this node
31599 this.ui = new uiClass(this);
31601 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31602 preventHScroll: true,
31604 * Returns true if this node is expanded
31605 * @return {Boolean}
31607 isExpanded : function(){
31608 return this.expanded;
31612 * Returns the UI object for this node
31613 * @return {TreeNodeUI}
31615 getUI : function(){
31619 // private override
31620 setFirstChild : function(node){
31621 var of = this.firstChild;
31622 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31623 if(this.childrenRendered && of && node != of){
31624 of.renderIndent(true, true);
31627 this.renderIndent(true, true);
31631 // private override
31632 setLastChild : function(node){
31633 var ol = this.lastChild;
31634 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31635 if(this.childrenRendered && ol && node != ol){
31636 ol.renderIndent(true, true);
31639 this.renderIndent(true, true);
31643 // these methods are overridden to provide lazy rendering support
31644 // private override
31645 appendChild : function(){
31646 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31647 if(node && this.childrenRendered){
31650 this.ui.updateExpandIcon();
31654 // private override
31655 removeChild : function(node){
31656 this.ownerTree.getSelectionModel().unselect(node);
31657 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31658 // if it's been rendered remove dom node
31659 if(this.childrenRendered){
31662 if(this.childNodes.length < 1){
31663 this.collapse(false, false);
31665 this.ui.updateExpandIcon();
31667 if(!this.firstChild) {
31668 this.childrenRendered = false;
31673 // private override
31674 insertBefore : function(node, refNode){
31675 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31676 if(newNode && refNode && this.childrenRendered){
31679 this.ui.updateExpandIcon();
31684 * Sets the text for this node
31685 * @param {String} text
31687 setText : function(text){
31688 var oldText = this.text;
31690 this.attributes.text = text;
31691 if(this.rendered){ // event without subscribing
31692 this.ui.onTextChange(this, text, oldText);
31694 this.fireEvent("textchange", this, text, oldText);
31698 * Triggers selection of this node
31700 select : function(){
31701 this.getOwnerTree().getSelectionModel().select(this);
31705 * Triggers deselection of this node
31707 unselect : function(){
31708 this.getOwnerTree().getSelectionModel().unselect(this);
31712 * Returns true if this node is selected
31713 * @return {Boolean}
31715 isSelected : function(){
31716 return this.getOwnerTree().getSelectionModel().isSelected(this);
31720 * Expand this node.
31721 * @param {Boolean} deep (optional) True to expand all children as well
31722 * @param {Boolean} anim (optional) false to cancel the default animation
31723 * @param {Function} callback (optional) A callback to be called when
31724 * expanding this node completes (does not wait for deep expand to complete).
31725 * Called with 1 parameter, this node.
31727 expand : function(deep, anim, callback){
31728 if(!this.expanded){
31729 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31732 if(!this.childrenRendered){
31733 this.renderChildren();
31735 this.expanded = true;
31736 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31737 this.ui.animExpand(function(){
31738 this.fireEvent("expand", this);
31739 if(typeof callback == "function"){
31743 this.expandChildNodes(true);
31745 }.createDelegate(this));
31749 this.fireEvent("expand", this);
31750 if(typeof callback == "function"){
31755 if(typeof callback == "function"){
31760 this.expandChildNodes(true);
31764 isHiddenRoot : function(){
31765 return this.isRoot && !this.getOwnerTree().rootVisible;
31769 * Collapse this node.
31770 * @param {Boolean} deep (optional) True to collapse all children as well
31771 * @param {Boolean} anim (optional) false to cancel the default animation
31773 collapse : function(deep, anim){
31774 if(this.expanded && !this.isHiddenRoot()){
31775 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31778 this.expanded = false;
31779 if((this.getOwnerTree().animate && anim !== false) || anim){
31780 this.ui.animCollapse(function(){
31781 this.fireEvent("collapse", this);
31783 this.collapseChildNodes(true);
31785 }.createDelegate(this));
31788 this.ui.collapse();
31789 this.fireEvent("collapse", this);
31793 var cs = this.childNodes;
31794 for(var i = 0, len = cs.length; i < len; i++) {
31795 cs[i].collapse(true, false);
31801 delayedExpand : function(delay){
31802 if(!this.expandProcId){
31803 this.expandProcId = this.expand.defer(delay, this);
31808 cancelExpand : function(){
31809 if(this.expandProcId){
31810 clearTimeout(this.expandProcId);
31812 this.expandProcId = false;
31816 * Toggles expanded/collapsed state of the node
31818 toggle : function(){
31827 * Ensures all parent nodes are expanded
31829 ensureVisible : function(callback){
31830 var tree = this.getOwnerTree();
31831 tree.expandPath(this.parentNode.getPath(), false, function(){
31832 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31833 Roo.callback(callback);
31834 }.createDelegate(this));
31838 * Expand all child nodes
31839 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31841 expandChildNodes : function(deep){
31842 var cs = this.childNodes;
31843 for(var i = 0, len = cs.length; i < len; i++) {
31844 cs[i].expand(deep);
31849 * Collapse all child nodes
31850 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31852 collapseChildNodes : function(deep){
31853 var cs = this.childNodes;
31854 for(var i = 0, len = cs.length; i < len; i++) {
31855 cs[i].collapse(deep);
31860 * Disables this node
31862 disable : function(){
31863 this.disabled = true;
31865 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31866 this.ui.onDisableChange(this, true);
31868 this.fireEvent("disabledchange", this, true);
31872 * Enables this node
31874 enable : function(){
31875 this.disabled = false;
31876 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31877 this.ui.onDisableChange(this, false);
31879 this.fireEvent("disabledchange", this, false);
31883 renderChildren : function(suppressEvent){
31884 if(suppressEvent !== false){
31885 this.fireEvent("beforechildrenrendered", this);
31887 var cs = this.childNodes;
31888 for(var i = 0, len = cs.length; i < len; i++){
31889 cs[i].render(true);
31891 this.childrenRendered = true;
31895 sort : function(fn, scope){
31896 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31897 if(this.childrenRendered){
31898 var cs = this.childNodes;
31899 for(var i = 0, len = cs.length; i < len; i++){
31900 cs[i].render(true);
31906 render : function(bulkRender){
31907 this.ui.render(bulkRender);
31908 if(!this.rendered){
31909 this.rendered = true;
31911 this.expanded = false;
31912 this.expand(false, false);
31918 renderIndent : function(deep, refresh){
31920 this.ui.childIndent = null;
31922 this.ui.renderIndent();
31923 if(deep === true && this.childrenRendered){
31924 var cs = this.childNodes;
31925 for(var i = 0, len = cs.length; i < len; i++){
31926 cs[i].renderIndent(true, refresh);
31932 * Ext JS Library 1.1.1
31933 * Copyright(c) 2006-2007, Ext JS, LLC.
31935 * Originally Released Under LGPL - original licence link has changed is not relivant.
31938 * <script type="text/javascript">
31942 * @class Roo.tree.AsyncTreeNode
31943 * @extends Roo.tree.TreeNode
31944 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31946 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31948 Roo.tree.AsyncTreeNode = function(config){
31949 this.loaded = false;
31950 this.loading = false;
31951 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31953 * @event beforeload
31954 * Fires before this node is loaded, return false to cancel
31955 * @param {Node} this This node
31957 this.addEvents({'beforeload':true, 'load': true});
31960 * Fires when this node is loaded
31961 * @param {Node} this This node
31964 * The loader used by this node (defaults to using the tree's defined loader)
31969 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31970 expand : function(deep, anim, callback){
31971 if(this.loading){ // if an async load is already running, waiting til it's done
31973 var f = function(){
31974 if(!this.loading){ // done loading
31975 clearInterval(timer);
31976 this.expand(deep, anim, callback);
31978 }.createDelegate(this);
31979 timer = setInterval(f, 200);
31983 if(this.fireEvent("beforeload", this) === false){
31986 this.loading = true;
31987 this.ui.beforeLoad(this);
31988 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31990 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31994 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31998 * Returns true if this node is currently loading
31999 * @return {Boolean}
32001 isLoading : function(){
32002 return this.loading;
32005 loadComplete : function(deep, anim, callback){
32006 this.loading = false;
32007 this.loaded = true;
32008 this.ui.afterLoad(this);
32009 this.fireEvent("load", this);
32010 this.expand(deep, anim, callback);
32014 * Returns true if this node has been loaded
32015 * @return {Boolean}
32017 isLoaded : function(){
32018 return this.loaded;
32021 hasChildNodes : function(){
32022 if(!this.isLeaf() && !this.loaded){
32025 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32030 * Trigger a reload for this node
32031 * @param {Function} callback
32033 reload : function(callback){
32034 this.collapse(false, false);
32035 while(this.firstChild){
32036 this.removeChild(this.firstChild);
32038 this.childrenRendered = false;
32039 this.loaded = false;
32040 if(this.isHiddenRoot()){
32041 this.expanded = false;
32043 this.expand(false, false, callback);
32047 * Ext JS Library 1.1.1
32048 * Copyright(c) 2006-2007, Ext JS, LLC.
32050 * Originally Released Under LGPL - original licence link has changed is not relivant.
32053 * <script type="text/javascript">
32057 * @class Roo.tree.TreeNodeUI
32059 * @param {Object} node The node to render
32060 * The TreeNode UI implementation is separate from the
32061 * tree implementation. Unless you are customizing the tree UI,
32062 * you should never have to use this directly.
32064 Roo.tree.TreeNodeUI = function(node){
32066 this.rendered = false;
32067 this.animating = false;
32068 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32071 Roo.tree.TreeNodeUI.prototype = {
32072 removeChild : function(node){
32074 this.ctNode.removeChild(node.ui.getEl());
32078 beforeLoad : function(){
32079 this.addClass("x-tree-node-loading");
32082 afterLoad : function(){
32083 this.removeClass("x-tree-node-loading");
32086 onTextChange : function(node, text, oldText){
32088 this.textNode.innerHTML = text;
32092 onDisableChange : function(node, state){
32093 this.disabled = state;
32095 this.addClass("x-tree-node-disabled");
32097 this.removeClass("x-tree-node-disabled");
32101 onSelectedChange : function(state){
32104 this.addClass("x-tree-selected");
32107 this.removeClass("x-tree-selected");
32111 onMove : function(tree, node, oldParent, newParent, index, refNode){
32112 this.childIndent = null;
32114 var targetNode = newParent.ui.getContainer();
32115 if(!targetNode){//target not rendered
32116 this.holder = document.createElement("div");
32117 this.holder.appendChild(this.wrap);
32120 var insertBefore = refNode ? refNode.ui.getEl() : null;
32122 targetNode.insertBefore(this.wrap, insertBefore);
32124 targetNode.appendChild(this.wrap);
32126 this.node.renderIndent(true);
32130 addClass : function(cls){
32132 Roo.fly(this.elNode).addClass(cls);
32136 removeClass : function(cls){
32138 Roo.fly(this.elNode).removeClass(cls);
32142 remove : function(){
32144 this.holder = document.createElement("div");
32145 this.holder.appendChild(this.wrap);
32149 fireEvent : function(){
32150 return this.node.fireEvent.apply(this.node, arguments);
32153 initEvents : function(){
32154 this.node.on("move", this.onMove, this);
32155 var E = Roo.EventManager;
32156 var a = this.anchor;
32158 var el = Roo.fly(a, '_treeui');
32160 if(Roo.isOpera){ // opera render bug ignores the CSS
32161 el.setStyle("text-decoration", "none");
32164 el.on("click", this.onClick, this);
32165 el.on("dblclick", this.onDblClick, this);
32168 Roo.EventManager.on(this.checkbox,
32169 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32172 el.on("contextmenu", this.onContextMenu, this);
32174 var icon = Roo.fly(this.iconNode);
32175 icon.on("click", this.onClick, this);
32176 icon.on("dblclick", this.onDblClick, this);
32177 icon.on("contextmenu", this.onContextMenu, this);
32178 E.on(this.ecNode, "click", this.ecClick, this, true);
32180 if(this.node.disabled){
32181 this.addClass("x-tree-node-disabled");
32183 if(this.node.hidden){
32184 this.addClass("x-tree-node-disabled");
32186 var ot = this.node.getOwnerTree();
32187 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32188 if(dd && (!this.node.isRoot || ot.rootVisible)){
32189 Roo.dd.Registry.register(this.elNode, {
32191 handles: this.getDDHandles(),
32197 getDDHandles : function(){
32198 return [this.iconNode, this.textNode];
32203 this.wrap.style.display = "none";
32209 this.wrap.style.display = "";
32213 onContextMenu : function(e){
32214 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32215 e.preventDefault();
32217 this.fireEvent("contextmenu", this.node, e);
32221 onClick : function(e){
32226 if(this.fireEvent("beforeclick", this.node, e) !== false){
32227 if(!this.disabled && this.node.attributes.href){
32228 this.fireEvent("click", this.node, e);
32231 e.preventDefault();
32236 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32237 this.node.toggle();
32240 this.fireEvent("click", this.node, e);
32246 onDblClick : function(e){
32247 e.preventDefault();
32252 this.toggleCheck();
32254 if(!this.animating && this.node.hasChildNodes()){
32255 this.node.toggle();
32257 this.fireEvent("dblclick", this.node, e);
32260 onCheckChange : function(){
32261 var checked = this.checkbox.checked;
32262 this.node.attributes.checked = checked;
32263 this.fireEvent('checkchange', this.node, checked);
32266 ecClick : function(e){
32267 if(!this.animating && this.node.hasChildNodes()){
32268 this.node.toggle();
32272 startDrop : function(){
32273 this.dropping = true;
32276 // delayed drop so the click event doesn't get fired on a drop
32277 endDrop : function(){
32278 setTimeout(function(){
32279 this.dropping = false;
32280 }.createDelegate(this), 50);
32283 expand : function(){
32284 this.updateExpandIcon();
32285 this.ctNode.style.display = "";
32288 focus : function(){
32289 if(!this.node.preventHScroll){
32290 try{this.anchor.focus();
32292 }else if(!Roo.isIE){
32294 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32295 var l = noscroll.scrollLeft;
32296 this.anchor.focus();
32297 noscroll.scrollLeft = l;
32302 toggleCheck : function(value){
32303 var cb = this.checkbox;
32305 cb.checked = (value === undefined ? !cb.checked : value);
32311 this.anchor.blur();
32315 animExpand : function(callback){
32316 var ct = Roo.get(this.ctNode);
32318 if(!this.node.hasChildNodes()){
32319 this.updateExpandIcon();
32320 this.ctNode.style.display = "";
32321 Roo.callback(callback);
32324 this.animating = true;
32325 this.updateExpandIcon();
32328 callback : function(){
32329 this.animating = false;
32330 Roo.callback(callback);
32333 duration: this.node.ownerTree.duration || .25
32337 highlight : function(){
32338 var tree = this.node.getOwnerTree();
32339 Roo.fly(this.wrap).highlight(
32340 tree.hlColor || "C3DAF9",
32341 {endColor: tree.hlBaseColor}
32345 collapse : function(){
32346 this.updateExpandIcon();
32347 this.ctNode.style.display = "none";
32350 animCollapse : function(callback){
32351 var ct = Roo.get(this.ctNode);
32352 ct.enableDisplayMode('block');
32355 this.animating = true;
32356 this.updateExpandIcon();
32359 callback : function(){
32360 this.animating = false;
32361 Roo.callback(callback);
32364 duration: this.node.ownerTree.duration || .25
32368 getContainer : function(){
32369 return this.ctNode;
32372 getEl : function(){
32376 appendDDGhost : function(ghostNode){
32377 ghostNode.appendChild(this.elNode.cloneNode(true));
32380 getDDRepairXY : function(){
32381 return Roo.lib.Dom.getXY(this.iconNode);
32384 onRender : function(){
32388 render : function(bulkRender){
32389 var n = this.node, a = n.attributes;
32390 var targetNode = n.parentNode ?
32391 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32393 if(!this.rendered){
32394 this.rendered = true;
32396 this.renderElements(n, a, targetNode, bulkRender);
32399 if(this.textNode.setAttributeNS){
32400 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32402 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32405 this.textNode.setAttribute("ext:qtip", a.qtip);
32407 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32410 }else if(a.qtipCfg){
32411 a.qtipCfg.target = Roo.id(this.textNode);
32412 Roo.QuickTips.register(a.qtipCfg);
32415 if(!this.node.expanded){
32416 this.updateExpandIcon();
32419 if(bulkRender === true) {
32420 targetNode.appendChild(this.wrap);
32425 renderElements : function(n, a, targetNode, bulkRender){
32426 // add some indent caching, this helps performance when rendering a large tree
32427 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32428 var t = n.getOwnerTree();
32429 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32430 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32431 var cb = typeof a.checked == 'boolean';
32432 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32433 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32434 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32435 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32436 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32437 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32438 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32439 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32440 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32441 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32444 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32445 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32446 n.nextSibling.ui.getEl(), buf.join(""));
32448 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32451 this.elNode = this.wrap.childNodes[0];
32452 this.ctNode = this.wrap.childNodes[1];
32453 var cs = this.elNode.childNodes;
32454 this.indentNode = cs[0];
32455 this.ecNode = cs[1];
32456 this.iconNode = cs[2];
32459 this.checkbox = cs[3];
32462 this.anchor = cs[index];
32463 this.textNode = cs[index].firstChild;
32466 getAnchor : function(){
32467 return this.anchor;
32470 getTextEl : function(){
32471 return this.textNode;
32474 getIconEl : function(){
32475 return this.iconNode;
32478 isChecked : function(){
32479 return this.checkbox ? this.checkbox.checked : false;
32482 updateExpandIcon : function(){
32484 var n = this.node, c1, c2;
32485 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32486 var hasChild = n.hasChildNodes();
32490 c1 = "x-tree-node-collapsed";
32491 c2 = "x-tree-node-expanded";
32494 c1 = "x-tree-node-expanded";
32495 c2 = "x-tree-node-collapsed";
32498 this.removeClass("x-tree-node-leaf");
32499 this.wasLeaf = false;
32501 if(this.c1 != c1 || this.c2 != c2){
32502 Roo.fly(this.elNode).replaceClass(c1, c2);
32503 this.c1 = c1; this.c2 = c2;
32507 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32510 this.wasLeaf = true;
32513 var ecc = "x-tree-ec-icon "+cls;
32514 if(this.ecc != ecc){
32515 this.ecNode.className = ecc;
32521 getChildIndent : function(){
32522 if(!this.childIndent){
32526 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32528 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32530 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32535 this.childIndent = buf.join("");
32537 return this.childIndent;
32540 renderIndent : function(){
32543 var p = this.node.parentNode;
32545 indent = p.ui.getChildIndent();
32547 if(this.indentMarkup != indent){ // don't rerender if not required
32548 this.indentNode.innerHTML = indent;
32549 this.indentMarkup = indent;
32551 this.updateExpandIcon();
32556 Roo.tree.RootTreeNodeUI = function(){
32557 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32559 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32560 render : function(){
32561 if(!this.rendered){
32562 var targetNode = this.node.ownerTree.innerCt.dom;
32563 this.node.expanded = true;
32564 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32565 this.wrap = this.ctNode = targetNode.firstChild;
32568 collapse : function(){
32570 expand : function(){
32574 * Ext JS Library 1.1.1
32575 * Copyright(c) 2006-2007, Ext JS, LLC.
32577 * Originally Released Under LGPL - original licence link has changed is not relivant.
32580 * <script type="text/javascript">
32583 * @class Roo.tree.TreeLoader
32584 * @extends Roo.util.Observable
32585 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32586 * nodes from a specified URL. The response must be a javascript Array definition
32587 * who's elements are node definition objects. eg:
32589 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32590 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32593 * A server request is sent, and child nodes are loaded only when a node is expanded.
32594 * The loading node's id is passed to the server under the parameter name "node" to
32595 * enable the server to produce the correct child nodes.
32597 * To pass extra parameters, an event handler may be attached to the "beforeload"
32598 * event, and the parameters specified in the TreeLoader's baseParams property:
32600 myTreeLoader.on("beforeload", function(treeLoader, node) {
32601 this.baseParams.category = node.attributes.category;
32604 * This would pass an HTTP parameter called "category" to the server containing
32605 * the value of the Node's "category" attribute.
32607 * Creates a new Treeloader.
32608 * @param {Object} config A config object containing config properties.
32610 Roo.tree.TreeLoader = function(config){
32611 this.baseParams = {};
32612 this.requestMethod = "POST";
32613 Roo.apply(this, config);
32618 * @event beforeload
32619 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32620 * @param {Object} This TreeLoader object.
32621 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32622 * @param {Object} callback The callback function specified in the {@link #load} call.
32627 * Fires when the node has been successfuly loaded.
32628 * @param {Object} This TreeLoader object.
32629 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32630 * @param {Object} response The response object containing the data from the server.
32634 * @event loadexception
32635 * Fires if the network request failed.
32636 * @param {Object} This TreeLoader object.
32637 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32638 * @param {Object} response The response object containing the data from the server.
32640 loadexception : true,
32643 * Fires before a node is created, enabling you to return custom Node types
32644 * @param {Object} This TreeLoader object.
32645 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32650 Roo.tree.TreeLoader.superclass.constructor.call(this);
32653 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32655 * @cfg {String} dataUrl The URL from which to request a Json string which
32656 * specifies an array of node definition object representing the child nodes
32660 * @cfg {Object} baseParams (optional) An object containing properties which
32661 * specify HTTP parameters to be passed to each request for child nodes.
32664 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32665 * created by this loader. If the attributes sent by the server have an attribute in this object,
32666 * they take priority.
32669 * @cfg {Object} uiProviders (optional) An object containing properties which
32671 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32672 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32673 * <i>uiProvider</i> attribute of a returned child node is a string rather
32674 * than a reference to a TreeNodeUI implementation, this that string value
32675 * is used as a property name in the uiProviders object. You can define the provider named
32676 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32681 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32682 * child nodes before loading.
32684 clearOnLoad : true,
32687 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32688 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32689 * Grid query { data : [ .....] }
32694 * @cfg {String} queryParam (optional)
32695 * Name of the query as it will be passed on the querystring (defaults to 'node')
32696 * eg. the request will be ?node=[id]
32703 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32704 * This is called automatically when a node is expanded, but may be used to reload
32705 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32706 * @param {Roo.tree.TreeNode} node
32707 * @param {Function} callback
32709 load : function(node, callback){
32710 if(this.clearOnLoad){
32711 while(node.firstChild){
32712 node.removeChild(node.firstChild);
32715 if(node.attributes.children){ // preloaded json children
32716 var cs = node.attributes.children;
32717 for(var i = 0, len = cs.length; i < len; i++){
32718 node.appendChild(this.createNode(cs[i]));
32720 if(typeof callback == "function"){
32723 }else if(this.dataUrl){
32724 this.requestData(node, callback);
32728 getParams: function(node){
32729 var buf = [], bp = this.baseParams;
32730 for(var key in bp){
32731 if(typeof bp[key] != "function"){
32732 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32735 var n = this.queryParam === false ? 'node' : this.queryParam;
32736 buf.push(n + "=", encodeURIComponent(node.id));
32737 return buf.join("");
32740 requestData : function(node, callback){
32741 if(this.fireEvent("beforeload", this, node, callback) !== false){
32742 this.transId = Roo.Ajax.request({
32743 method:this.requestMethod,
32744 url: this.dataUrl||this.url,
32745 success: this.handleResponse,
32746 failure: this.handleFailure,
32748 argument: {callback: callback, node: node},
32749 params: this.getParams(node)
32752 // if the load is cancelled, make sure we notify
32753 // the node that we are done
32754 if(typeof callback == "function"){
32760 isLoading : function(){
32761 return this.transId ? true : false;
32764 abort : function(){
32765 if(this.isLoading()){
32766 Roo.Ajax.abort(this.transId);
32771 createNode : function(attr){
32772 // apply baseAttrs, nice idea Corey!
32773 if(this.baseAttrs){
32774 Roo.applyIf(attr, this.baseAttrs);
32776 if(this.applyLoader !== false){
32777 attr.loader = this;
32779 // uiProvider = depreciated..
32781 if(typeof(attr.uiProvider) == 'string'){
32782 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32783 /** eval:var:attr */ eval(attr.uiProvider);
32785 if(typeof(this.uiProviders['default']) != 'undefined') {
32786 attr.uiProvider = this.uiProviders['default'];
32789 this.fireEvent('create', this, attr);
32791 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32793 new Roo.tree.TreeNode(attr) :
32794 new Roo.tree.AsyncTreeNode(attr));
32797 processResponse : function(response, node, callback){
32798 var json = response.responseText;
32801 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32802 if (this.root !== false) {
32806 for(var i = 0, len = o.length; i < len; i++){
32807 var n = this.createNode(o[i]);
32809 node.appendChild(n);
32812 if(typeof callback == "function"){
32813 callback(this, node);
32816 this.handleFailure(response);
32820 handleResponse : function(response){
32821 this.transId = false;
32822 var a = response.argument;
32823 this.processResponse(response, a.node, a.callback);
32824 this.fireEvent("load", this, a.node, response);
32827 handleFailure : function(response){
32828 this.transId = false;
32829 var a = response.argument;
32830 this.fireEvent("loadexception", this, a.node, response);
32831 if(typeof a.callback == "function"){
32832 a.callback(this, a.node);
32837 * Ext JS Library 1.1.1
32838 * Copyright(c) 2006-2007, Ext JS, LLC.
32840 * Originally Released Under LGPL - original licence link has changed is not relivant.
32843 * <script type="text/javascript">
32847 * @class Roo.tree.TreeFilter
32848 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32849 * @param {TreePanel} tree
32850 * @param {Object} config (optional)
32852 Roo.tree.TreeFilter = function(tree, config){
32854 this.filtered = {};
32855 Roo.apply(this, config);
32858 Roo.tree.TreeFilter.prototype = {
32865 * Filter the data by a specific attribute.
32866 * @param {String/RegExp} value Either string that the attribute value
32867 * should start with or a RegExp to test against the attribute
32868 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32869 * @param {TreeNode} startNode (optional) The node to start the filter at.
32871 filter : function(value, attr, startNode){
32872 attr = attr || "text";
32874 if(typeof value == "string"){
32875 var vlen = value.length;
32876 // auto clear empty filter
32877 if(vlen == 0 && this.clearBlank){
32881 value = value.toLowerCase();
32883 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32885 }else if(value.exec){ // regex?
32887 return value.test(n.attributes[attr]);
32890 throw 'Illegal filter type, must be string or regex';
32892 this.filterBy(f, null, startNode);
32896 * Filter by a function. The passed function will be called with each
32897 * node in the tree (or from the startNode). If the function returns true, the node is kept
32898 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32899 * @param {Function} fn The filter function
32900 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32902 filterBy : function(fn, scope, startNode){
32903 startNode = startNode || this.tree.root;
32904 if(this.autoClear){
32907 var af = this.filtered, rv = this.reverse;
32908 var f = function(n){
32909 if(n == startNode){
32915 var m = fn.call(scope || n, n);
32923 startNode.cascade(f);
32926 if(typeof id != "function"){
32928 if(n && n.parentNode){
32929 n.parentNode.removeChild(n);
32937 * Clears the current filter. Note: with the "remove" option
32938 * set a filter cannot be cleared.
32940 clear : function(){
32942 var af = this.filtered;
32944 if(typeof id != "function"){
32951 this.filtered = {};
32956 * Ext JS Library 1.1.1
32957 * Copyright(c) 2006-2007, Ext JS, LLC.
32959 * Originally Released Under LGPL - original licence link has changed is not relivant.
32962 * <script type="text/javascript">
32967 * @class Roo.tree.TreeSorter
32968 * Provides sorting of nodes in a TreePanel
32970 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32971 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32972 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32973 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32974 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32975 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32977 * @param {TreePanel} tree
32978 * @param {Object} config
32980 Roo.tree.TreeSorter = function(tree, config){
32981 Roo.apply(this, config);
32982 tree.on("beforechildrenrendered", this.doSort, this);
32983 tree.on("append", this.updateSort, this);
32984 tree.on("insert", this.updateSort, this);
32986 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32987 var p = this.property || "text";
32988 var sortType = this.sortType;
32989 var fs = this.folderSort;
32990 var cs = this.caseSensitive === true;
32991 var leafAttr = this.leafAttr || 'leaf';
32993 this.sortFn = function(n1, n2){
32995 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32998 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33002 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33003 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33005 return dsc ? +1 : -1;
33007 return dsc ? -1 : +1;
33014 Roo.tree.TreeSorter.prototype = {
33015 doSort : function(node){
33016 node.sort(this.sortFn);
33019 compareNodes : function(n1, n2){
33020 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33023 updateSort : function(tree, node){
33024 if(node.childrenRendered){
33025 this.doSort.defer(1, this, [node]);
33030 * Ext JS Library 1.1.1
33031 * Copyright(c) 2006-2007, Ext JS, LLC.
33033 * Originally Released Under LGPL - original licence link has changed is not relivant.
33036 * <script type="text/javascript">
33039 if(Roo.dd.DropZone){
33041 Roo.tree.TreeDropZone = function(tree, config){
33042 this.allowParentInsert = false;
33043 this.allowContainerDrop = false;
33044 this.appendOnly = false;
33045 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33047 this.lastInsertClass = "x-tree-no-status";
33048 this.dragOverData = {};
33051 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33052 ddGroup : "TreeDD",
33054 expandDelay : 1000,
33056 expandNode : function(node){
33057 if(node.hasChildNodes() && !node.isExpanded()){
33058 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33062 queueExpand : function(node){
33063 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33066 cancelExpand : function(){
33067 if(this.expandProcId){
33068 clearTimeout(this.expandProcId);
33069 this.expandProcId = false;
33073 isValidDropPoint : function(n, pt, dd, e, data){
33074 if(!n || !data){ return false; }
33075 var targetNode = n.node;
33076 var dropNode = data.node;
33077 // default drop rules
33078 if(!(targetNode && targetNode.isTarget && pt)){
33081 if(pt == "append" && targetNode.allowChildren === false){
33084 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33087 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33090 // reuse the object
33091 var overEvent = this.dragOverData;
33092 overEvent.tree = this.tree;
33093 overEvent.target = targetNode;
33094 overEvent.data = data;
33095 overEvent.point = pt;
33096 overEvent.source = dd;
33097 overEvent.rawEvent = e;
33098 overEvent.dropNode = dropNode;
33099 overEvent.cancel = false;
33100 var result = this.tree.fireEvent("nodedragover", overEvent);
33101 return overEvent.cancel === false && result !== false;
33104 getDropPoint : function(e, n, dd){
33107 return tn.allowChildren !== false ? "append" : false; // always append for root
33109 var dragEl = n.ddel;
33110 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33111 var y = Roo.lib.Event.getPageY(e);
33112 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33114 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33115 var noAppend = tn.allowChildren === false;
33116 if(this.appendOnly || tn.parentNode.allowChildren === false){
33117 return noAppend ? false : "append";
33119 var noBelow = false;
33120 if(!this.allowParentInsert){
33121 noBelow = tn.hasChildNodes() && tn.isExpanded();
33123 var q = (b - t) / (noAppend ? 2 : 3);
33124 if(y >= t && y < (t + q)){
33126 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33133 onNodeEnter : function(n, dd, e, data){
33134 this.cancelExpand();
33137 onNodeOver : function(n, dd, e, data){
33138 var pt = this.getDropPoint(e, n, dd);
33141 // auto node expand check
33142 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33143 this.queueExpand(node);
33144 }else if(pt != "append"){
33145 this.cancelExpand();
33148 // set the insert point style on the target node
33149 var returnCls = this.dropNotAllowed;
33150 if(this.isValidDropPoint(n, pt, dd, e, data)){
33155 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33156 cls = "x-tree-drag-insert-above";
33157 }else if(pt == "below"){
33158 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33159 cls = "x-tree-drag-insert-below";
33161 returnCls = "x-tree-drop-ok-append";
33162 cls = "x-tree-drag-append";
33164 if(this.lastInsertClass != cls){
33165 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33166 this.lastInsertClass = cls;
33173 onNodeOut : function(n, dd, e, data){
33174 this.cancelExpand();
33175 this.removeDropIndicators(n);
33178 onNodeDrop : function(n, dd, e, data){
33179 var point = this.getDropPoint(e, n, dd);
33180 var targetNode = n.node;
33181 targetNode.ui.startDrop();
33182 if(!this.isValidDropPoint(n, point, dd, e, data)){
33183 targetNode.ui.endDrop();
33186 // first try to find the drop node
33187 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33190 target: targetNode,
33195 dropNode: dropNode,
33198 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33199 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33200 targetNode.ui.endDrop();
33203 // allow target changing
33204 targetNode = dropEvent.target;
33205 if(point == "append" && !targetNode.isExpanded()){
33206 targetNode.expand(false, null, function(){
33207 this.completeDrop(dropEvent);
33208 }.createDelegate(this));
33210 this.completeDrop(dropEvent);
33215 completeDrop : function(de){
33216 var ns = de.dropNode, p = de.point, t = de.target;
33217 if(!(ns instanceof Array)){
33221 for(var i = 0, len = ns.length; i < len; i++){
33224 t.parentNode.insertBefore(n, t);
33225 }else if(p == "below"){
33226 t.parentNode.insertBefore(n, t.nextSibling);
33232 if(this.tree.hlDrop){
33236 this.tree.fireEvent("nodedrop", de);
33239 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33240 if(this.tree.hlDrop){
33241 dropNode.ui.focus();
33242 dropNode.ui.highlight();
33244 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33247 getTree : function(){
33251 removeDropIndicators : function(n){
33254 Roo.fly(el).removeClass([
33255 "x-tree-drag-insert-above",
33256 "x-tree-drag-insert-below",
33257 "x-tree-drag-append"]);
33258 this.lastInsertClass = "_noclass";
33262 beforeDragDrop : function(target, e, id){
33263 this.cancelExpand();
33267 afterRepair : function(data){
33268 if(data && Roo.enableFx){
33269 data.node.ui.highlight();
33278 * Ext JS Library 1.1.1
33279 * Copyright(c) 2006-2007, Ext JS, LLC.
33281 * Originally Released Under LGPL - original licence link has changed is not relivant.
33284 * <script type="text/javascript">
33288 if(Roo.dd.DragZone){
33289 Roo.tree.TreeDragZone = function(tree, config){
33290 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33294 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33295 ddGroup : "TreeDD",
33297 onBeforeDrag : function(data, e){
33299 return n && n.draggable && !n.disabled;
33302 onInitDrag : function(e){
33303 var data = this.dragData;
33304 this.tree.getSelectionModel().select(data.node);
33305 this.proxy.update("");
33306 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33307 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33310 getRepairXY : function(e, data){
33311 return data.node.ui.getDDRepairXY();
33314 onEndDrag : function(data, e){
33315 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33318 onValidDrop : function(dd, e, id){
33319 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33323 beforeInvalidDrop : function(e, id){
33324 // this scrolls the original position back into view
33325 var sm = this.tree.getSelectionModel();
33326 sm.clearSelections();
33327 sm.select(this.dragData.node);
33332 * Ext JS Library 1.1.1
33333 * Copyright(c) 2006-2007, Ext JS, LLC.
33335 * Originally Released Under LGPL - original licence link has changed is not relivant.
33338 * <script type="text/javascript">
33341 * @class Roo.tree.TreeEditor
33342 * @extends Roo.Editor
33343 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33344 * as the editor field.
33346 * @param {TreePanel} tree
33347 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33349 Roo.tree.TreeEditor = function(tree, config){
33350 config = config || {};
33351 var field = config.events ? config : new Roo.form.TextField(config);
33352 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33356 tree.on('beforeclick', this.beforeNodeClick, this);
33357 tree.getTreeEl().on('mousedown', this.hide, this);
33358 this.on('complete', this.updateNode, this);
33359 this.on('beforestartedit', this.fitToTree, this);
33360 this.on('startedit', this.bindScroll, this, {delay:10});
33361 this.on('specialkey', this.onSpecialKey, this);
33364 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33366 * @cfg {String} alignment
33367 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33373 * @cfg {Boolean} hideEl
33374 * True to hide the bound element while the editor is displayed (defaults to false)
33378 * @cfg {String} cls
33379 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33381 cls: "x-small-editor x-tree-editor",
33383 * @cfg {Boolean} shim
33384 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33390 * @cfg {Number} maxWidth
33391 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33392 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33393 * scroll and client offsets into account prior to each edit.
33400 fitToTree : function(ed, el){
33401 var td = this.tree.getTreeEl().dom, nd = el.dom;
33402 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33403 td.scrollLeft = nd.offsetLeft;
33407 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33408 this.setSize(w, '');
33412 triggerEdit : function(node){
33413 this.completeEdit();
33414 this.editNode = node;
33415 this.startEdit(node.ui.textNode, node.text);
33419 bindScroll : function(){
33420 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33424 beforeNodeClick : function(node, e){
33425 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33426 this.lastClick = new Date();
33427 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33429 this.triggerEdit(node);
33435 updateNode : function(ed, value){
33436 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33437 this.editNode.setText(value);
33441 onHide : function(){
33442 Roo.tree.TreeEditor.superclass.onHide.call(this);
33444 this.editNode.ui.focus();
33449 onSpecialKey : function(field, e){
33450 var k = e.getKey();
33454 }else if(k == e.ENTER && !e.hasModifier()){
33456 this.completeEdit();
33459 });//<Script type="text/javascript">
33462 * Ext JS Library 1.1.1
33463 * Copyright(c) 2006-2007, Ext JS, LLC.
33465 * Originally Released Under LGPL - original licence link has changed is not relivant.
33468 * <script type="text/javascript">
33472 * Not documented??? - probably should be...
33475 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33476 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33478 renderElements : function(n, a, targetNode, bulkRender){
33479 //consel.log("renderElements?");
33480 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33482 var t = n.getOwnerTree();
33483 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33485 var cols = t.columns;
33486 var bw = t.borderWidth;
33488 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33489 var cb = typeof a.checked == "boolean";
33490 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33491 var colcls = 'x-t-' + tid + '-c0';
33493 '<li class="x-tree-node">',
33496 '<div class="x-tree-node-el ', a.cls,'">',
33498 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33501 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33502 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33503 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33504 (a.icon ? ' x-tree-node-inline-icon' : ''),
33505 (a.iconCls ? ' '+a.iconCls : ''),
33506 '" unselectable="on" />',
33507 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33508 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33510 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33511 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33512 '<span unselectable="on" qtip="' + tx + '">',
33516 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33517 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33519 for(var i = 1, len = cols.length; i < len; i++){
33521 colcls = 'x-t-' + tid + '-c' +i;
33522 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33523 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33524 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33530 '<div class="x-clear"></div></div>',
33531 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33534 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33535 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33536 n.nextSibling.ui.getEl(), buf.join(""));
33538 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33540 var el = this.wrap.firstChild;
33542 this.elNode = el.firstChild;
33543 this.ranchor = el.childNodes[1];
33544 this.ctNode = this.wrap.childNodes[1];
33545 var cs = el.firstChild.childNodes;
33546 this.indentNode = cs[0];
33547 this.ecNode = cs[1];
33548 this.iconNode = cs[2];
33551 this.checkbox = cs[3];
33554 this.anchor = cs[index];
33556 this.textNode = cs[index].firstChild;
33558 //el.on("click", this.onClick, this);
33559 //el.on("dblclick", this.onDblClick, this);
33562 // console.log(this);
33564 initEvents : function(){
33565 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33568 var a = this.ranchor;
33570 var el = Roo.get(a);
33572 if(Roo.isOpera){ // opera render bug ignores the CSS
33573 el.setStyle("text-decoration", "none");
33576 el.on("click", this.onClick, this);
33577 el.on("dblclick", this.onDblClick, this);
33578 el.on("contextmenu", this.onContextMenu, this);
33582 /*onSelectedChange : function(state){
33585 this.addClass("x-tree-selected");
33588 this.removeClass("x-tree-selected");
33591 addClass : function(cls){
33593 Roo.fly(this.elRow).addClass(cls);
33599 removeClass : function(cls){
33601 Roo.fly(this.elRow).removeClass(cls);
33607 });//<Script type="text/javascript">
33611 * Ext JS Library 1.1.1
33612 * Copyright(c) 2006-2007, Ext JS, LLC.
33614 * Originally Released Under LGPL - original licence link has changed is not relivant.
33617 * <script type="text/javascript">
33622 * @class Roo.tree.ColumnTree
33623 * @extends Roo.data.TreePanel
33624 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33625 * @cfg {int} borderWidth compined right/left border allowance
33627 * @param {String/HTMLElement/Element} el The container element
33628 * @param {Object} config
33630 Roo.tree.ColumnTree = function(el, config)
33632 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33636 * Fire this event on a container when it resizes
33637 * @param {int} w Width
33638 * @param {int} h Height
33642 this.on('resize', this.onResize, this);
33645 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33649 borderWidth: Roo.isBorderBox ? 0 : 2,
33652 render : function(){
33653 // add the header.....
33655 Roo.tree.ColumnTree.superclass.render.apply(this);
33657 this.el.addClass('x-column-tree');
33659 this.headers = this.el.createChild(
33660 {cls:'x-tree-headers'},this.innerCt.dom);
33662 var cols = this.columns, c;
33663 var totalWidth = 0;
33665 var len = cols.length;
33666 for(var i = 0; i < len; i++){
33668 totalWidth += c.width;
33669 this.headEls.push(this.headers.createChild({
33670 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33672 cls:'x-tree-hd-text',
33675 style:'width:'+(c.width-this.borderWidth)+'px;'
33678 this.headers.createChild({cls:'x-clear'});
33679 // prevent floats from wrapping when clipped
33680 this.headers.setWidth(totalWidth);
33681 //this.innerCt.setWidth(totalWidth);
33682 this.innerCt.setStyle({ overflow: 'auto' });
33683 this.onResize(this.width, this.height);
33687 onResize : function(w,h)
33692 this.innerCt.setWidth(this.width);
33693 this.innerCt.setHeight(this.height-20);
33696 var cols = this.columns, c;
33697 var totalWidth = 0;
33699 var len = cols.length;
33700 for(var i = 0; i < len; i++){
33702 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33703 // it's the expander..
33704 expEl = this.headEls[i];
33707 totalWidth += c.width;
33711 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33713 this.headers.setWidth(w-20);
33722 * Ext JS Library 1.1.1
33723 * Copyright(c) 2006-2007, Ext JS, LLC.
33725 * Originally Released Under LGPL - original licence link has changed is not relivant.
33728 * <script type="text/javascript">
33732 * @class Roo.menu.Menu
33733 * @extends Roo.util.Observable
33734 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33735 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33737 * Creates a new Menu
33738 * @param {Object} config Configuration options
33740 Roo.menu.Menu = function(config){
33741 Roo.apply(this, config);
33742 this.id = this.id || Roo.id();
33745 * @event beforeshow
33746 * Fires before this menu is displayed
33747 * @param {Roo.menu.Menu} this
33751 * @event beforehide
33752 * Fires before this menu is hidden
33753 * @param {Roo.menu.Menu} this
33758 * Fires after this menu is displayed
33759 * @param {Roo.menu.Menu} this
33764 * Fires after this menu is hidden
33765 * @param {Roo.menu.Menu} this
33770 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33771 * @param {Roo.menu.Menu} this
33772 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33773 * @param {Roo.EventObject} e
33778 * Fires when the mouse is hovering over this menu
33779 * @param {Roo.menu.Menu} this
33780 * @param {Roo.EventObject} e
33781 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33786 * Fires when the mouse exits this menu
33787 * @param {Roo.menu.Menu} this
33788 * @param {Roo.EventObject} e
33789 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33794 * Fires when a menu item contained in this menu is clicked
33795 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33796 * @param {Roo.EventObject} e
33800 if (this.registerMenu) {
33801 Roo.menu.MenuMgr.register(this);
33804 var mis = this.items;
33805 this.items = new Roo.util.MixedCollection();
33807 this.add.apply(this, mis);
33811 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33813 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33817 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33818 * for bottom-right shadow (defaults to "sides")
33822 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33823 * this menu (defaults to "tl-tr?")
33825 subMenuAlign : "tl-tr?",
33827 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33828 * relative to its element of origin (defaults to "tl-bl?")
33830 defaultAlign : "tl-bl?",
33832 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33834 allowOtherMenus : false,
33836 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33838 registerMenu : true,
33843 render : function(){
33847 var el = this.el = new Roo.Layer({
33849 shadow:this.shadow,
33851 parentEl: this.parentEl || document.body,
33855 this.keyNav = new Roo.menu.MenuNav(this);
33858 el.addClass("x-menu-plain");
33861 el.addClass(this.cls);
33863 // generic focus element
33864 this.focusEl = el.createChild({
33865 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33867 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33868 ul.on("click", this.onClick, this);
33869 ul.on("mouseover", this.onMouseOver, this);
33870 ul.on("mouseout", this.onMouseOut, this);
33871 this.items.each(function(item){
33872 var li = document.createElement("li");
33873 li.className = "x-menu-list-item";
33874 ul.dom.appendChild(li);
33875 item.render(li, this);
33882 autoWidth : function(){
33883 var el = this.el, ul = this.ul;
33887 var w = this.width;
33890 }else if(Roo.isIE){
33891 el.setWidth(this.minWidth);
33892 var t = el.dom.offsetWidth; // force recalc
33893 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33898 delayAutoWidth : function(){
33901 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33903 this.awTask.delay(20);
33908 findTargetItem : function(e){
33909 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33910 if(t && t.menuItemId){
33911 return this.items.get(t.menuItemId);
33916 onClick : function(e){
33918 if(t = this.findTargetItem(e)){
33920 this.fireEvent("click", this, t, e);
33925 setActiveItem : function(item, autoExpand){
33926 if(item != this.activeItem){
33927 if(this.activeItem){
33928 this.activeItem.deactivate();
33930 this.activeItem = item;
33931 item.activate(autoExpand);
33932 }else if(autoExpand){
33938 tryActivate : function(start, step){
33939 var items = this.items;
33940 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33941 var item = items.get(i);
33942 if(!item.disabled && item.canActivate){
33943 this.setActiveItem(item, false);
33951 onMouseOver : function(e){
33953 if(t = this.findTargetItem(e)){
33954 if(t.canActivate && !t.disabled){
33955 this.setActiveItem(t, true);
33958 this.fireEvent("mouseover", this, e, t);
33962 onMouseOut : function(e){
33964 if(t = this.findTargetItem(e)){
33965 if(t == this.activeItem && t.shouldDeactivate(e)){
33966 this.activeItem.deactivate();
33967 delete this.activeItem;
33970 this.fireEvent("mouseout", this, e, t);
33974 * Read-only. Returns true if the menu is currently displayed, else false.
33977 isVisible : function(){
33978 return this.el && !this.hidden;
33982 * Displays this menu relative to another element
33983 * @param {String/HTMLElement/Roo.Element} element The element to align to
33984 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33985 * the element (defaults to this.defaultAlign)
33986 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33988 show : function(el, pos, parentMenu){
33989 this.parentMenu = parentMenu;
33993 this.fireEvent("beforeshow", this);
33994 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33998 * Displays this menu at a specific xy position
33999 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34000 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34002 showAt : function(xy, parentMenu, /* private: */_e){
34003 this.parentMenu = parentMenu;
34008 this.fireEvent("beforeshow", this);
34009 xy = this.el.adjustForConstraints(xy);
34013 this.hidden = false;
34015 this.fireEvent("show", this);
34018 focus : function(){
34020 this.doFocus.defer(50, this);
34024 doFocus : function(){
34026 this.focusEl.focus();
34031 * Hides this menu and optionally all parent menus
34032 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34034 hide : function(deep){
34035 if(this.el && this.isVisible()){
34036 this.fireEvent("beforehide", this);
34037 if(this.activeItem){
34038 this.activeItem.deactivate();
34039 this.activeItem = null;
34042 this.hidden = true;
34043 this.fireEvent("hide", this);
34045 if(deep === true && this.parentMenu){
34046 this.parentMenu.hide(true);
34051 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34052 * Any of the following are valid:
34054 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34055 * <li>An HTMLElement object which will be converted to a menu item</li>
34056 * <li>A menu item config object that will be created as a new menu item</li>
34057 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34058 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34063 var menu = new Roo.menu.Menu();
34065 // Create a menu item to add by reference
34066 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34068 // Add a bunch of items at once using different methods.
34069 // Only the last item added will be returned.
34070 var item = menu.add(
34071 menuItem, // add existing item by ref
34072 'Dynamic Item', // new TextItem
34073 '-', // new separator
34074 { text: 'Config Item' } // new item by config
34077 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34078 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34081 var a = arguments, l = a.length, item;
34082 for(var i = 0; i < l; i++){
34084 if ((typeof(el) == "object") && el.xtype && el.xns) {
34085 el = Roo.factory(el, Roo.menu);
34088 if(el.render){ // some kind of Item
34089 item = this.addItem(el);
34090 }else if(typeof el == "string"){ // string
34091 if(el == "separator" || el == "-"){
34092 item = this.addSeparator();
34094 item = this.addText(el);
34096 }else if(el.tagName || el.el){ // element
34097 item = this.addElement(el);
34098 }else if(typeof el == "object"){ // must be menu item config?
34099 item = this.addMenuItem(el);
34106 * Returns this menu's underlying {@link Roo.Element} object
34107 * @return {Roo.Element} The element
34109 getEl : function(){
34117 * Adds a separator bar to the menu
34118 * @return {Roo.menu.Item} The menu item that was added
34120 addSeparator : function(){
34121 return this.addItem(new Roo.menu.Separator());
34125 * Adds an {@link Roo.Element} object to the menu
34126 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34127 * @return {Roo.menu.Item} The menu item that was added
34129 addElement : function(el){
34130 return this.addItem(new Roo.menu.BaseItem(el));
34134 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34135 * @param {Roo.menu.Item} item The menu item to add
34136 * @return {Roo.menu.Item} The menu item that was added
34138 addItem : function(item){
34139 this.items.add(item);
34141 var li = document.createElement("li");
34142 li.className = "x-menu-list-item";
34143 this.ul.dom.appendChild(li);
34144 item.render(li, this);
34145 this.delayAutoWidth();
34151 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34152 * @param {Object} config A MenuItem config object
34153 * @return {Roo.menu.Item} The menu item that was added
34155 addMenuItem : function(config){
34156 if(!(config instanceof Roo.menu.Item)){
34157 if(typeof config.checked == "boolean"){ // must be check menu item config?
34158 config = new Roo.menu.CheckItem(config);
34160 config = new Roo.menu.Item(config);
34163 return this.addItem(config);
34167 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34168 * @param {String} text The text to display in the menu item
34169 * @return {Roo.menu.Item} The menu item that was added
34171 addText : function(text){
34172 return this.addItem(new Roo.menu.TextItem({ text : text }));
34176 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34177 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34178 * @param {Roo.menu.Item} item The menu item to add
34179 * @return {Roo.menu.Item} The menu item that was added
34181 insert : function(index, item){
34182 this.items.insert(index, item);
34184 var li = document.createElement("li");
34185 li.className = "x-menu-list-item";
34186 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34187 item.render(li, this);
34188 this.delayAutoWidth();
34194 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34195 * @param {Roo.menu.Item} item The menu item to remove
34197 remove : function(item){
34198 this.items.removeKey(item.id);
34203 * Removes and destroys all items in the menu
34205 removeAll : function(){
34207 while(f = this.items.first()){
34213 // MenuNav is a private utility class used internally by the Menu
34214 Roo.menu.MenuNav = function(menu){
34215 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34216 this.scope = this.menu = menu;
34219 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34220 doRelay : function(e, h){
34221 var k = e.getKey();
34222 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34223 this.menu.tryActivate(0, 1);
34226 return h.call(this.scope || this, e, this.menu);
34229 up : function(e, m){
34230 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34231 m.tryActivate(m.items.length-1, -1);
34235 down : function(e, m){
34236 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34237 m.tryActivate(0, 1);
34241 right : function(e, m){
34243 m.activeItem.expandMenu(true);
34247 left : function(e, m){
34249 if(m.parentMenu && m.parentMenu.activeItem){
34250 m.parentMenu.activeItem.activate();
34254 enter : function(e, m){
34256 e.stopPropagation();
34257 m.activeItem.onClick(e);
34258 m.fireEvent("click", this, m.activeItem);
34264 * Ext JS Library 1.1.1
34265 * Copyright(c) 2006-2007, Ext JS, LLC.
34267 * Originally Released Under LGPL - original licence link has changed is not relivant.
34270 * <script type="text/javascript">
34274 * @class Roo.menu.MenuMgr
34275 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34278 Roo.menu.MenuMgr = function(){
34279 var menus, active, groups = {}, attached = false, lastShow = new Date();
34281 // private - called when first menu is created
34284 active = new Roo.util.MixedCollection();
34285 Roo.get(document).addKeyListener(27, function(){
34286 if(active.length > 0){
34293 function hideAll(){
34294 if(active && active.length > 0){
34295 var c = active.clone();
34296 c.each(function(m){
34303 function onHide(m){
34305 if(active.length < 1){
34306 Roo.get(document).un("mousedown", onMouseDown);
34312 function onShow(m){
34313 var last = active.last();
34314 lastShow = new Date();
34317 Roo.get(document).on("mousedown", onMouseDown);
34321 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34322 m.parentMenu.activeChild = m;
34323 }else if(last && last.isVisible()){
34324 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34329 function onBeforeHide(m){
34331 m.activeChild.hide();
34333 if(m.autoHideTimer){
34334 clearTimeout(m.autoHideTimer);
34335 delete m.autoHideTimer;
34340 function onBeforeShow(m){
34341 var pm = m.parentMenu;
34342 if(!pm && !m.allowOtherMenus){
34344 }else if(pm && pm.activeChild && active != m){
34345 pm.activeChild.hide();
34350 function onMouseDown(e){
34351 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34357 function onBeforeCheck(mi, state){
34359 var g = groups[mi.group];
34360 for(var i = 0, l = g.length; i < l; i++){
34362 g[i].setChecked(false);
34371 * Hides all menus that are currently visible
34373 hideAll : function(){
34378 register : function(menu){
34382 menus[menu.id] = menu;
34383 menu.on("beforehide", onBeforeHide);
34384 menu.on("hide", onHide);
34385 menu.on("beforeshow", onBeforeShow);
34386 menu.on("show", onShow);
34387 var g = menu.group;
34388 if(g && menu.events["checkchange"]){
34392 groups[g].push(menu);
34393 menu.on("checkchange", onCheck);
34398 * Returns a {@link Roo.menu.Menu} object
34399 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34400 * be used to generate and return a new Menu instance.
34402 get : function(menu){
34403 if(typeof menu == "string"){ // menu id
34404 return menus[menu];
34405 }else if(menu.events){ // menu instance
34407 }else if(typeof menu.length == 'number'){ // array of menu items?
34408 return new Roo.menu.Menu({items:menu});
34409 }else{ // otherwise, must be a config
34410 return new Roo.menu.Menu(menu);
34415 unregister : function(menu){
34416 delete menus[menu.id];
34417 menu.un("beforehide", onBeforeHide);
34418 menu.un("hide", onHide);
34419 menu.un("beforeshow", onBeforeShow);
34420 menu.un("show", onShow);
34421 var g = menu.group;
34422 if(g && menu.events["checkchange"]){
34423 groups[g].remove(menu);
34424 menu.un("checkchange", onCheck);
34429 registerCheckable : function(menuItem){
34430 var g = menuItem.group;
34435 groups[g].push(menuItem);
34436 menuItem.on("beforecheckchange", onBeforeCheck);
34441 unregisterCheckable : function(menuItem){
34442 var g = menuItem.group;
34444 groups[g].remove(menuItem);
34445 menuItem.un("beforecheckchange", onBeforeCheck);
34451 * Ext JS Library 1.1.1
34452 * Copyright(c) 2006-2007, Ext JS, LLC.
34454 * Originally Released Under LGPL - original licence link has changed is not relivant.
34457 * <script type="text/javascript">
34462 * @class Roo.menu.BaseItem
34463 * @extends Roo.Component
34464 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34465 * management and base configuration options shared by all menu components.
34467 * Creates a new BaseItem
34468 * @param {Object} config Configuration options
34470 Roo.menu.BaseItem = function(config){
34471 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34476 * Fires when this item is clicked
34477 * @param {Roo.menu.BaseItem} this
34478 * @param {Roo.EventObject} e
34483 * Fires when this item is activated
34484 * @param {Roo.menu.BaseItem} this
34488 * @event deactivate
34489 * Fires when this item is deactivated
34490 * @param {Roo.menu.BaseItem} this
34496 this.on("click", this.handler, this.scope, true);
34500 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34502 * @cfg {Function} handler
34503 * A function that will handle the click event of this menu item (defaults to undefined)
34506 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34508 canActivate : false,
34510 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34512 activeClass : "x-menu-item-active",
34514 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34516 hideOnClick : true,
34518 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34523 ctype: "Roo.menu.BaseItem",
34526 actionMode : "container",
34529 render : function(container, parentMenu){
34530 this.parentMenu = parentMenu;
34531 Roo.menu.BaseItem.superclass.render.call(this, container);
34532 this.container.menuItemId = this.id;
34536 onRender : function(container, position){
34537 this.el = Roo.get(this.el);
34538 container.dom.appendChild(this.el.dom);
34542 onClick : function(e){
34543 if(!this.disabled && this.fireEvent("click", this, e) !== false
34544 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34545 this.handleClick(e);
34552 activate : function(){
34556 var li = this.container;
34557 li.addClass(this.activeClass);
34558 this.region = li.getRegion().adjust(2, 2, -2, -2);
34559 this.fireEvent("activate", this);
34564 deactivate : function(){
34565 this.container.removeClass(this.activeClass);
34566 this.fireEvent("deactivate", this);
34570 shouldDeactivate : function(e){
34571 return !this.region || !this.region.contains(e.getPoint());
34575 handleClick : function(e){
34576 if(this.hideOnClick){
34577 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34582 expandMenu : function(autoActivate){
34587 hideMenu : function(){
34592 * Ext JS Library 1.1.1
34593 * Copyright(c) 2006-2007, Ext JS, LLC.
34595 * Originally Released Under LGPL - original licence link has changed is not relivant.
34598 * <script type="text/javascript">
34602 * @class Roo.menu.Adapter
34603 * @extends Roo.menu.BaseItem
34604 * 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.
34605 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34607 * Creates a new Adapter
34608 * @param {Object} config Configuration options
34610 Roo.menu.Adapter = function(component, config){
34611 Roo.menu.Adapter.superclass.constructor.call(this, config);
34612 this.component = component;
34614 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34616 canActivate : true,
34619 onRender : function(container, position){
34620 this.component.render(container);
34621 this.el = this.component.getEl();
34625 activate : function(){
34629 this.component.focus();
34630 this.fireEvent("activate", this);
34635 deactivate : function(){
34636 this.fireEvent("deactivate", this);
34640 disable : function(){
34641 this.component.disable();
34642 Roo.menu.Adapter.superclass.disable.call(this);
34646 enable : function(){
34647 this.component.enable();
34648 Roo.menu.Adapter.superclass.enable.call(this);
34652 * Ext JS Library 1.1.1
34653 * Copyright(c) 2006-2007, Ext JS, LLC.
34655 * Originally Released Under LGPL - original licence link has changed is not relivant.
34658 * <script type="text/javascript">
34662 * @class Roo.menu.TextItem
34663 * @extends Roo.menu.BaseItem
34664 * Adds a static text string to a menu, usually used as either a heading or group separator.
34665 * Note: old style constructor with text is still supported.
34668 * Creates a new TextItem
34669 * @param {Object} cfg Configuration
34671 Roo.menu.TextItem = function(cfg){
34672 if (typeof(cfg) == 'string') {
34675 Roo.apply(this,cfg);
34678 Roo.menu.TextItem.superclass.constructor.call(this);
34681 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34683 * @cfg {Boolean} text Text to show on item.
34688 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34690 hideOnClick : false,
34692 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34694 itemCls : "x-menu-text",
34697 onRender : function(){
34698 var s = document.createElement("span");
34699 s.className = this.itemCls;
34700 s.innerHTML = this.text;
34702 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34706 * Ext JS Library 1.1.1
34707 * Copyright(c) 2006-2007, Ext JS, LLC.
34709 * Originally Released Under LGPL - original licence link has changed is not relivant.
34712 * <script type="text/javascript">
34716 * @class Roo.menu.Separator
34717 * @extends Roo.menu.BaseItem
34718 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34719 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34721 * @param {Object} config Configuration options
34723 Roo.menu.Separator = function(config){
34724 Roo.menu.Separator.superclass.constructor.call(this, config);
34727 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34729 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34731 itemCls : "x-menu-sep",
34733 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34735 hideOnClick : false,
34738 onRender : function(li){
34739 var s = document.createElement("span");
34740 s.className = this.itemCls;
34741 s.innerHTML = " ";
34743 li.addClass("x-menu-sep-li");
34744 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34748 * Ext JS Library 1.1.1
34749 * Copyright(c) 2006-2007, Ext JS, LLC.
34751 * Originally Released Under LGPL - original licence link has changed is not relivant.
34754 * <script type="text/javascript">
34757 * @class Roo.menu.Item
34758 * @extends Roo.menu.BaseItem
34759 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34760 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34761 * activation and click handling.
34763 * Creates a new Item
34764 * @param {Object} config Configuration options
34766 Roo.menu.Item = function(config){
34767 Roo.menu.Item.superclass.constructor.call(this, config);
34769 this.menu = Roo.menu.MenuMgr.get(this.menu);
34772 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34775 * @cfg {String} text
34776 * The text to show on the menu item.
34780 * @cfg {String} HTML to render in menu
34781 * The text to show on the menu item (HTML version).
34785 * @cfg {String} icon
34786 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34790 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34792 itemCls : "x-menu-item",
34794 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34796 canActivate : true,
34798 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34801 // doc'd in BaseItem
34805 ctype: "Roo.menu.Item",
34808 onRender : function(container, position){
34809 var el = document.createElement("a");
34810 el.hideFocus = true;
34811 el.unselectable = "on";
34812 el.href = this.href || "#";
34813 if(this.hrefTarget){
34814 el.target = this.hrefTarget;
34816 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34818 var html = this.html.length ? this.html : String.format('{0}',this.text);
34820 el.innerHTML = String.format(
34821 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34822 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34824 Roo.menu.Item.superclass.onRender.call(this, container, position);
34828 * Sets the text to display in this menu item
34829 * @param {String} text The text to display
34830 * @param {Boolean} isHTML true to indicate text is pure html.
34832 setText : function(text, isHTML){
34840 var html = this.html.length ? this.html : String.format('{0}',this.text);
34842 this.el.update(String.format(
34843 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34844 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34845 this.parentMenu.autoWidth();
34850 handleClick : function(e){
34851 if(!this.href){ // if no link defined, stop the event automatically
34854 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34858 activate : function(autoExpand){
34859 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34869 shouldDeactivate : function(e){
34870 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34871 if(this.menu && this.menu.isVisible()){
34872 return !this.menu.getEl().getRegion().contains(e.getPoint());
34880 deactivate : function(){
34881 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34886 expandMenu : function(autoActivate){
34887 if(!this.disabled && this.menu){
34888 clearTimeout(this.hideTimer);
34889 delete this.hideTimer;
34890 if(!this.menu.isVisible() && !this.showTimer){
34891 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34892 }else if (this.menu.isVisible() && autoActivate){
34893 this.menu.tryActivate(0, 1);
34899 deferExpand : function(autoActivate){
34900 delete this.showTimer;
34901 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34903 this.menu.tryActivate(0, 1);
34908 hideMenu : function(){
34909 clearTimeout(this.showTimer);
34910 delete this.showTimer;
34911 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34912 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34917 deferHide : function(){
34918 delete this.hideTimer;
34923 * Ext JS Library 1.1.1
34924 * Copyright(c) 2006-2007, Ext JS, LLC.
34926 * Originally Released Under LGPL - original licence link has changed is not relivant.
34929 * <script type="text/javascript">
34933 * @class Roo.menu.CheckItem
34934 * @extends Roo.menu.Item
34935 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34937 * Creates a new CheckItem
34938 * @param {Object} config Configuration options
34940 Roo.menu.CheckItem = function(config){
34941 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34944 * @event beforecheckchange
34945 * Fires before the checked value is set, providing an opportunity to cancel if needed
34946 * @param {Roo.menu.CheckItem} this
34947 * @param {Boolean} checked The new checked value that will be set
34949 "beforecheckchange" : true,
34951 * @event checkchange
34952 * Fires after the checked value has been set
34953 * @param {Roo.menu.CheckItem} this
34954 * @param {Boolean} checked The checked value that was set
34956 "checkchange" : true
34958 if(this.checkHandler){
34959 this.on('checkchange', this.checkHandler, this.scope);
34962 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34964 * @cfg {String} group
34965 * All check items with the same group name will automatically be grouped into a single-select
34966 * radio button group (defaults to '')
34969 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34971 itemCls : "x-menu-item x-menu-check-item",
34973 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34975 groupClass : "x-menu-group-item",
34978 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34979 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34980 * initialized with checked = true will be rendered as checked.
34985 ctype: "Roo.menu.CheckItem",
34988 onRender : function(c){
34989 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34991 this.el.addClass(this.groupClass);
34993 Roo.menu.MenuMgr.registerCheckable(this);
34995 this.checked = false;
34996 this.setChecked(true, true);
35001 destroy : function(){
35003 Roo.menu.MenuMgr.unregisterCheckable(this);
35005 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35009 * Set the checked state of this item
35010 * @param {Boolean} checked The new checked value
35011 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35013 setChecked : function(state, suppressEvent){
35014 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35015 if(this.container){
35016 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35018 this.checked = state;
35019 if(suppressEvent !== true){
35020 this.fireEvent("checkchange", this, state);
35026 handleClick : function(e){
35027 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35028 this.setChecked(!this.checked);
35030 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35034 * Ext JS Library 1.1.1
35035 * Copyright(c) 2006-2007, Ext JS, LLC.
35037 * Originally Released Under LGPL - original licence link has changed is not relivant.
35040 * <script type="text/javascript">
35044 * @class Roo.menu.DateItem
35045 * @extends Roo.menu.Adapter
35046 * A menu item that wraps the {@link Roo.DatPicker} component.
35048 * Creates a new DateItem
35049 * @param {Object} config Configuration options
35051 Roo.menu.DateItem = function(config){
35052 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35053 /** The Roo.DatePicker object @type Roo.DatePicker */
35054 this.picker = this.component;
35055 this.addEvents({select: true});
35057 this.picker.on("render", function(picker){
35058 picker.getEl().swallowEvent("click");
35059 picker.container.addClass("x-menu-date-item");
35062 this.picker.on("select", this.onSelect, this);
35065 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35067 onSelect : function(picker, date){
35068 this.fireEvent("select", this, date, picker);
35069 Roo.menu.DateItem.superclass.handleClick.call(this);
35073 * Ext JS Library 1.1.1
35074 * Copyright(c) 2006-2007, Ext JS, LLC.
35076 * Originally Released Under LGPL - original licence link has changed is not relivant.
35079 * <script type="text/javascript">
35083 * @class Roo.menu.ColorItem
35084 * @extends Roo.menu.Adapter
35085 * A menu item that wraps the {@link Roo.ColorPalette} component.
35087 * Creates a new ColorItem
35088 * @param {Object} config Configuration options
35090 Roo.menu.ColorItem = function(config){
35091 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35092 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35093 this.palette = this.component;
35094 this.relayEvents(this.palette, ["select"]);
35095 if(this.selectHandler){
35096 this.on('select', this.selectHandler, this.scope);
35099 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35101 * Ext JS Library 1.1.1
35102 * Copyright(c) 2006-2007, Ext JS, LLC.
35104 * Originally Released Under LGPL - original licence link has changed is not relivant.
35107 * <script type="text/javascript">
35112 * @class Roo.menu.DateMenu
35113 * @extends Roo.menu.Menu
35114 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35116 * Creates a new DateMenu
35117 * @param {Object} config Configuration options
35119 Roo.menu.DateMenu = function(config){
35120 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35122 var di = new Roo.menu.DateItem(config);
35125 * The {@link Roo.DatePicker} instance for this DateMenu
35128 this.picker = di.picker;
35131 * @param {DatePicker} picker
35132 * @param {Date} date
35134 this.relayEvents(di, ["select"]);
35136 this.on('beforeshow', function(){
35138 this.picker.hideMonthPicker(true);
35142 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35146 * Ext JS Library 1.1.1
35147 * Copyright(c) 2006-2007, Ext JS, LLC.
35149 * Originally Released Under LGPL - original licence link has changed is not relivant.
35152 * <script type="text/javascript">
35157 * @class Roo.menu.ColorMenu
35158 * @extends Roo.menu.Menu
35159 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35161 * Creates a new ColorMenu
35162 * @param {Object} config Configuration options
35164 Roo.menu.ColorMenu = function(config){
35165 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35167 var ci = new Roo.menu.ColorItem(config);
35170 * The {@link Roo.ColorPalette} instance for this ColorMenu
35171 * @type ColorPalette
35173 this.palette = ci.palette;
35176 * @param {ColorPalette} palette
35177 * @param {String} color
35179 this.relayEvents(ci, ["select"]);
35181 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35183 * Ext JS Library 1.1.1
35184 * Copyright(c) 2006-2007, Ext JS, LLC.
35186 * Originally Released Under LGPL - original licence link has changed is not relivant.
35189 * <script type="text/javascript">
35193 * @class Roo.form.Field
35194 * @extends Roo.BoxComponent
35195 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35197 * Creates a new Field
35198 * @param {Object} config Configuration options
35200 Roo.form.Field = function(config){
35201 Roo.form.Field.superclass.constructor.call(this, config);
35204 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35206 * @cfg {String} fieldLabel Label to use when rendering a form.
35209 * @cfg {String} qtip Mouse over tip
35213 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35215 invalidClass : "x-form-invalid",
35217 * @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")
35219 invalidText : "The value in this field is invalid",
35221 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35223 focusClass : "x-form-focus",
35225 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35226 automatic validation (defaults to "keyup").
35228 validationEvent : "keyup",
35230 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35232 validateOnBlur : true,
35234 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35236 validationDelay : 250,
35238 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35239 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35241 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35243 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35245 fieldClass : "x-form-field",
35247 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35250 ----------- ----------------------------------------------------------------------
35251 qtip Display a quick tip when the user hovers over the field
35252 title Display a default browser title attribute popup
35253 under Add a block div beneath the field containing the error text
35254 side Add an error icon to the right of the field with a popup on hover
35255 [element id] Add the error text directly to the innerHTML of the specified element
35258 msgTarget : 'qtip',
35260 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35265 * @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.
35270 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35275 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35277 inputType : undefined,
35280 * @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).
35282 tabIndex : undefined,
35285 isFormField : true,
35290 * @property {Roo.Element} fieldEl
35291 * Element Containing the rendered Field (with label etc.)
35294 * @cfg {Mixed} value A value to initialize this field with.
35299 * @cfg {String} name The field's HTML name attribute.
35302 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35306 initComponent : function(){
35307 Roo.form.Field.superclass.initComponent.call(this);
35311 * Fires when this field receives input focus.
35312 * @param {Roo.form.Field} this
35317 * Fires when this field loses input focus.
35318 * @param {Roo.form.Field} this
35322 * @event specialkey
35323 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35324 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35325 * @param {Roo.form.Field} this
35326 * @param {Roo.EventObject} e The event object
35331 * Fires just before the field blurs if the field value has changed.
35332 * @param {Roo.form.Field} this
35333 * @param {Mixed} newValue The new value
35334 * @param {Mixed} oldValue The original value
35339 * Fires after the field has been marked as invalid.
35340 * @param {Roo.form.Field} this
35341 * @param {String} msg The validation message
35346 * Fires after the field has been validated with no errors.
35347 * @param {Roo.form.Field} this
35352 * Fires after the key up
35353 * @param {Roo.form.Field} this
35354 * @param {Roo.EventObject} e The event Object
35361 * Returns the name attribute of the field if available
35362 * @return {String} name The field name
35364 getName: function(){
35365 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35369 onRender : function(ct, position){
35370 Roo.form.Field.superclass.onRender.call(this, ct, position);
35372 var cfg = this.getAutoCreate();
35374 cfg.name = this.name || this.id;
35376 if(this.inputType){
35377 cfg.type = this.inputType;
35379 this.el = ct.createChild(cfg, position);
35381 var type = this.el.dom.type;
35383 if(type == 'password'){
35386 this.el.addClass('x-form-'+type);
35389 this.el.dom.readOnly = true;
35391 if(this.tabIndex !== undefined){
35392 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35395 this.el.addClass([this.fieldClass, this.cls]);
35400 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35401 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35402 * @return {Roo.form.Field} this
35404 applyTo : function(target){
35405 this.allowDomMove = false;
35406 this.el = Roo.get(target);
35407 this.render(this.el.dom.parentNode);
35412 initValue : function(){
35413 if(this.value !== undefined){
35414 this.setValue(this.value);
35415 }else if(this.el.dom.value.length > 0){
35416 this.setValue(this.el.dom.value);
35421 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35423 isDirty : function() {
35424 if(this.disabled) {
35427 return String(this.getValue()) !== String(this.originalValue);
35431 afterRender : function(){
35432 Roo.form.Field.superclass.afterRender.call(this);
35437 fireKey : function(e){
35438 //Roo.log('field ' + e.getKey());
35439 if(e.isNavKeyPress()){
35440 this.fireEvent("specialkey", this, e);
35445 * Resets the current field value to the originally loaded value and clears any validation messages
35447 reset : function(){
35448 this.setValue(this.originalValue);
35449 this.clearInvalid();
35453 initEvents : function(){
35454 // safari killled keypress - so keydown is now used..
35455 this.el.on("keydown" , this.fireKey, this);
35456 this.el.on("focus", this.onFocus, this);
35457 this.el.on("blur", this.onBlur, this);
35458 this.el.relayEvent('keyup', this);
35460 // reference to original value for reset
35461 this.originalValue = this.getValue();
35465 onFocus : function(){
35466 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35467 this.el.addClass(this.focusClass);
35469 if(!this.hasFocus){
35470 this.hasFocus = true;
35471 this.startValue = this.getValue();
35472 this.fireEvent("focus", this);
35476 beforeBlur : Roo.emptyFn,
35479 onBlur : function(){
35481 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35482 this.el.removeClass(this.focusClass);
35484 this.hasFocus = false;
35485 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35488 var v = this.getValue();
35489 if(String(v) !== String(this.startValue)){
35490 this.fireEvent('change', this, v, this.startValue);
35492 this.fireEvent("blur", this);
35496 * Returns whether or not the field value is currently valid
35497 * @param {Boolean} preventMark True to disable marking the field invalid
35498 * @return {Boolean} True if the value is valid, else false
35500 isValid : function(preventMark){
35504 var restore = this.preventMark;
35505 this.preventMark = preventMark === true;
35506 var v = this.validateValue(this.processValue(this.getRawValue()));
35507 this.preventMark = restore;
35512 * Validates the field value
35513 * @return {Boolean} True if the value is valid, else false
35515 validate : function(){
35516 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35517 this.clearInvalid();
35523 processValue : function(value){
35528 // Subclasses should provide the validation implementation by overriding this
35529 validateValue : function(value){
35534 * Mark this field as invalid
35535 * @param {String} msg The validation message
35537 markInvalid : function(msg){
35538 if(!this.rendered || this.preventMark){ // not rendered
35541 this.el.addClass(this.invalidClass);
35542 msg = msg || this.invalidText;
35543 switch(this.msgTarget){
35545 this.el.dom.qtip = msg;
35546 this.el.dom.qclass = 'x-form-invalid-tip';
35547 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35548 Roo.QuickTips.enable();
35552 this.el.dom.title = msg;
35556 var elp = this.el.findParent('.x-form-element', 5, true);
35557 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35558 this.errorEl.setWidth(elp.getWidth(true)-20);
35560 this.errorEl.update(msg);
35561 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35564 if(!this.errorIcon){
35565 var elp = this.el.findParent('.x-form-element', 5, true);
35566 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35568 this.alignErrorIcon();
35569 this.errorIcon.dom.qtip = msg;
35570 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35571 this.errorIcon.show();
35572 this.on('resize', this.alignErrorIcon, this);
35575 var t = Roo.getDom(this.msgTarget);
35577 t.style.display = this.msgDisplay;
35580 this.fireEvent('invalid', this, msg);
35584 alignErrorIcon : function(){
35585 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35589 * Clear any invalid styles/messages for this field
35591 clearInvalid : function(){
35592 if(!this.rendered || this.preventMark){ // not rendered
35595 this.el.removeClass(this.invalidClass);
35596 switch(this.msgTarget){
35598 this.el.dom.qtip = '';
35601 this.el.dom.title = '';
35605 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35609 if(this.errorIcon){
35610 this.errorIcon.dom.qtip = '';
35611 this.errorIcon.hide();
35612 this.un('resize', this.alignErrorIcon, this);
35616 var t = Roo.getDom(this.msgTarget);
35618 t.style.display = 'none';
35621 this.fireEvent('valid', this);
35625 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35626 * @return {Mixed} value The field value
35628 getRawValue : function(){
35629 var v = this.el.getValue();
35630 if(v === this.emptyText){
35637 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35638 * @return {Mixed} value The field value
35640 getValue : function(){
35641 var v = this.el.getValue();
35642 if(v === this.emptyText || v === undefined){
35649 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35650 * @param {Mixed} value The value to set
35652 setRawValue : function(v){
35653 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35657 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35658 * @param {Mixed} value The value to set
35660 setValue : function(v){
35663 this.el.dom.value = (v === null || v === undefined ? '' : v);
35668 adjustSize : function(w, h){
35669 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35670 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35674 adjustWidth : function(tag, w){
35675 tag = tag.toLowerCase();
35676 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35677 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35678 if(tag == 'input'){
35681 if(tag = 'textarea'){
35684 }else if(Roo.isOpera){
35685 if(tag == 'input'){
35688 if(tag = 'textarea'){
35698 // anything other than normal should be considered experimental
35699 Roo.form.Field.msgFx = {
35701 show: function(msgEl, f){
35702 msgEl.setDisplayed('block');
35705 hide : function(msgEl, f){
35706 msgEl.setDisplayed(false).update('');
35711 show: function(msgEl, f){
35712 msgEl.slideIn('t', {stopFx:true});
35715 hide : function(msgEl, f){
35716 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35721 show: function(msgEl, f){
35722 msgEl.fixDisplay();
35723 msgEl.alignTo(f.el, 'tl-tr');
35724 msgEl.slideIn('l', {stopFx:true});
35727 hide : function(msgEl, f){
35728 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35733 * Ext JS Library 1.1.1
35734 * Copyright(c) 2006-2007, Ext JS, LLC.
35736 * Originally Released Under LGPL - original licence link has changed is not relivant.
35739 * <script type="text/javascript">
35744 * @class Roo.form.TextField
35745 * @extends Roo.form.Field
35746 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35747 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35749 * Creates a new TextField
35750 * @param {Object} config Configuration options
35752 Roo.form.TextField = function(config){
35753 Roo.form.TextField.superclass.constructor.call(this, config);
35757 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35758 * according to the default logic, but this event provides a hook for the developer to apply additional
35759 * logic at runtime to resize the field if needed.
35760 * @param {Roo.form.Field} this This text field
35761 * @param {Number} width The new field width
35767 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35769 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35773 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35777 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35781 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35785 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35789 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35791 disableKeyFilter : false,
35793 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35797 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35801 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35803 maxLength : Number.MAX_VALUE,
35805 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35807 minLengthText : "The minimum length for this field is {0}",
35809 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35811 maxLengthText : "The maximum length for this field is {0}",
35813 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35815 selectOnFocus : false,
35817 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35819 blankText : "This field is required",
35821 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35822 * If available, this function will be called only after the basic validators all return true, and will be passed the
35823 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35827 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35828 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35829 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35833 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35837 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35841 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35842 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35844 emptyClass : 'x-form-empty-field',
35847 initEvents : function(){
35848 Roo.form.TextField.superclass.initEvents.call(this);
35849 if(this.validationEvent == 'keyup'){
35850 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35851 this.el.on('keyup', this.filterValidation, this);
35853 else if(this.validationEvent !== false){
35854 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35856 if(this.selectOnFocus || this.emptyText){
35857 this.on("focus", this.preFocus, this);
35858 if(this.emptyText){
35859 this.on('blur', this.postBlur, this);
35860 this.applyEmptyText();
35863 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35864 this.el.on("keypress", this.filterKeys, this);
35867 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35868 this.el.on("click", this.autoSize, this);
35872 processValue : function(value){
35873 if(this.stripCharsRe){
35874 var newValue = value.replace(this.stripCharsRe, '');
35875 if(newValue !== value){
35876 this.setRawValue(newValue);
35883 filterValidation : function(e){
35884 if(!e.isNavKeyPress()){
35885 this.validationTask.delay(this.validationDelay);
35890 onKeyUp : function(e){
35891 if(!e.isNavKeyPress()){
35897 * Resets the current field value to the originally-loaded value and clears any validation messages.
35898 * Also adds emptyText and emptyClass if the original value was blank.
35900 reset : function(){
35901 Roo.form.TextField.superclass.reset.call(this);
35902 this.applyEmptyText();
35905 applyEmptyText : function(){
35906 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35907 this.setRawValue(this.emptyText);
35908 this.el.addClass(this.emptyClass);
35913 preFocus : function(){
35914 if(this.emptyText){
35915 if(this.el.dom.value == this.emptyText){
35916 this.setRawValue('');
35918 this.el.removeClass(this.emptyClass);
35920 if(this.selectOnFocus){
35921 this.el.dom.select();
35926 postBlur : function(){
35927 this.applyEmptyText();
35931 filterKeys : function(e){
35932 var k = e.getKey();
35933 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35936 var c = e.getCharCode(), cc = String.fromCharCode(c);
35937 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35940 if(!this.maskRe.test(cc)){
35945 setValue : function(v){
35946 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35947 this.el.removeClass(this.emptyClass);
35949 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35950 this.applyEmptyText();
35955 * Validates a value according to the field's validation rules and marks the field as invalid
35956 * if the validation fails
35957 * @param {Mixed} value The value to validate
35958 * @return {Boolean} True if the value is valid, else false
35960 validateValue : function(value){
35961 if(value.length < 1 || value === this.emptyText){ // if it's blank
35962 if(this.allowBlank){
35963 this.clearInvalid();
35966 this.markInvalid(this.blankText);
35970 if(value.length < this.minLength){
35971 this.markInvalid(String.format(this.minLengthText, this.minLength));
35974 if(value.length > this.maxLength){
35975 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35979 var vt = Roo.form.VTypes;
35980 if(!vt[this.vtype](value, this)){
35981 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35985 if(typeof this.validator == "function"){
35986 var msg = this.validator(value);
35988 this.markInvalid(msg);
35992 if(this.regex && !this.regex.test(value)){
35993 this.markInvalid(this.regexText);
36000 * Selects text in this field
36001 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36002 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36004 selectText : function(start, end){
36005 var v = this.getRawValue();
36007 start = start === undefined ? 0 : start;
36008 end = end === undefined ? v.length : end;
36009 var d = this.el.dom;
36010 if(d.setSelectionRange){
36011 d.setSelectionRange(start, end);
36012 }else if(d.createTextRange){
36013 var range = d.createTextRange();
36014 range.moveStart("character", start);
36015 range.moveEnd("character", v.length-end);
36022 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36023 * This only takes effect if grow = true, and fires the autosize event.
36025 autoSize : function(){
36026 if(!this.grow || !this.rendered){
36030 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36033 var v = el.dom.value;
36034 var d = document.createElement('div');
36035 d.appendChild(document.createTextNode(v));
36039 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36040 this.el.setWidth(w);
36041 this.fireEvent("autosize", this, w);
36045 * Ext JS Library 1.1.1
36046 * Copyright(c) 2006-2007, Ext JS, LLC.
36048 * Originally Released Under LGPL - original licence link has changed is not relivant.
36051 * <script type="text/javascript">
36055 * @class Roo.form.Hidden
36056 * @extends Roo.form.TextField
36057 * Simple Hidden element used on forms
36059 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36062 * Creates a new Hidden form element.
36063 * @param {Object} config Configuration options
36068 // easy hidden field...
36069 Roo.form.Hidden = function(config){
36070 Roo.form.Hidden.superclass.constructor.call(this, config);
36073 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36075 inputType: 'hidden',
36078 labelSeparator: '',
36080 itemCls : 'x-form-item-display-none'
36088 * Ext JS Library 1.1.1
36089 * Copyright(c) 2006-2007, Ext JS, LLC.
36091 * Originally Released Under LGPL - original licence link has changed is not relivant.
36094 * <script type="text/javascript">
36098 * @class Roo.form.TriggerField
36099 * @extends Roo.form.TextField
36100 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36101 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36102 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36103 * for which you can provide a custom implementation. For example:
36105 var trigger = new Roo.form.TriggerField();
36106 trigger.onTriggerClick = myTriggerFn;
36107 trigger.applyTo('my-field');
36110 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36111 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36112 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36113 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36115 * Create a new TriggerField.
36116 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36117 * to the base TextField)
36119 Roo.form.TriggerField = function(config){
36120 this.mimicing = false;
36121 Roo.form.TriggerField.superclass.constructor.call(this, config);
36124 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36126 * @cfg {String} triggerClass A CSS class to apply to the trigger
36129 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36130 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36132 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36134 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36138 /** @cfg {Boolean} grow @hide */
36139 /** @cfg {Number} growMin @hide */
36140 /** @cfg {Number} growMax @hide */
36146 autoSize: Roo.emptyFn,
36150 deferHeight : true,
36153 actionMode : 'wrap',
36155 onResize : function(w, h){
36156 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36157 if(typeof w == 'number'){
36158 var x = w - this.trigger.getWidth();
36159 this.el.setWidth(this.adjustWidth('input', x));
36160 this.trigger.setStyle('left', x+'px');
36165 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36168 getResizeEl : function(){
36173 getPositionEl : function(){
36178 alignErrorIcon : function(){
36179 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36183 onRender : function(ct, position){
36184 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36185 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36186 this.trigger = this.wrap.createChild(this.triggerConfig ||
36187 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36188 if(this.hideTrigger){
36189 this.trigger.setDisplayed(false);
36191 this.initTrigger();
36193 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36198 initTrigger : function(){
36199 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36200 this.trigger.addClassOnOver('x-form-trigger-over');
36201 this.trigger.addClassOnClick('x-form-trigger-click');
36205 onDestroy : function(){
36207 this.trigger.removeAllListeners();
36208 this.trigger.remove();
36211 this.wrap.remove();
36213 Roo.form.TriggerField.superclass.onDestroy.call(this);
36217 onFocus : function(){
36218 Roo.form.TriggerField.superclass.onFocus.call(this);
36219 if(!this.mimicing){
36220 this.wrap.addClass('x-trigger-wrap-focus');
36221 this.mimicing = true;
36222 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36223 if(this.monitorTab){
36224 this.el.on("keydown", this.checkTab, this);
36230 checkTab : function(e){
36231 if(e.getKey() == e.TAB){
36232 this.triggerBlur();
36237 onBlur : function(){
36242 mimicBlur : function(e, t){
36243 if(!this.wrap.contains(t) && this.validateBlur()){
36244 this.triggerBlur();
36249 triggerBlur : function(){
36250 this.mimicing = false;
36251 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36252 if(this.monitorTab){
36253 this.el.un("keydown", this.checkTab, this);
36255 this.wrap.removeClass('x-trigger-wrap-focus');
36256 Roo.form.TriggerField.superclass.onBlur.call(this);
36260 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36261 validateBlur : function(e, t){
36266 onDisable : function(){
36267 Roo.form.TriggerField.superclass.onDisable.call(this);
36269 this.wrap.addClass('x-item-disabled');
36274 onEnable : function(){
36275 Roo.form.TriggerField.superclass.onEnable.call(this);
36277 this.wrap.removeClass('x-item-disabled');
36282 onShow : function(){
36283 var ae = this.getActionEl();
36286 ae.dom.style.display = '';
36287 ae.dom.style.visibility = 'visible';
36293 onHide : function(){
36294 var ae = this.getActionEl();
36295 ae.dom.style.display = 'none';
36299 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36300 * by an implementing function.
36302 * @param {EventObject} e
36304 onTriggerClick : Roo.emptyFn
36307 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36308 // to be extended by an implementing class. For an example of implementing this class, see the custom
36309 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36310 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36311 initComponent : function(){
36312 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36314 this.triggerConfig = {
36315 tag:'span', cls:'x-form-twin-triggers', cn:[
36316 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36317 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36321 getTrigger : function(index){
36322 return this.triggers[index];
36325 initTrigger : function(){
36326 var ts = this.trigger.select('.x-form-trigger', true);
36327 this.wrap.setStyle('overflow', 'hidden');
36328 var triggerField = this;
36329 ts.each(function(t, all, index){
36330 t.hide = function(){
36331 var w = triggerField.wrap.getWidth();
36332 this.dom.style.display = 'none';
36333 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36335 t.show = function(){
36336 var w = triggerField.wrap.getWidth();
36337 this.dom.style.display = '';
36338 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36340 var triggerIndex = 'Trigger'+(index+1);
36342 if(this['hide'+triggerIndex]){
36343 t.dom.style.display = 'none';
36345 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36346 t.addClassOnOver('x-form-trigger-over');
36347 t.addClassOnClick('x-form-trigger-click');
36349 this.triggers = ts.elements;
36352 onTrigger1Click : Roo.emptyFn,
36353 onTrigger2Click : Roo.emptyFn
36356 * Ext JS Library 1.1.1
36357 * Copyright(c) 2006-2007, Ext JS, LLC.
36359 * Originally Released Under LGPL - original licence link has changed is not relivant.
36362 * <script type="text/javascript">
36366 * @class Roo.form.TextArea
36367 * @extends Roo.form.TextField
36368 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36369 * support for auto-sizing.
36371 * Creates a new TextArea
36372 * @param {Object} config Configuration options
36374 Roo.form.TextArea = function(config){
36375 Roo.form.TextArea.superclass.constructor.call(this, config);
36376 // these are provided exchanges for backwards compat
36377 // minHeight/maxHeight were replaced by growMin/growMax to be
36378 // compatible with TextField growing config values
36379 if(this.minHeight !== undefined){
36380 this.growMin = this.minHeight;
36382 if(this.maxHeight !== undefined){
36383 this.growMax = this.maxHeight;
36387 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36389 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36393 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36397 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36398 * in the field (equivalent to setting overflow: hidden, defaults to false)
36400 preventScrollbars: false,
36402 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36403 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36407 onRender : function(ct, position){
36409 this.defaultAutoCreate = {
36411 style:"width:300px;height:60px;",
36412 autocomplete: "off"
36415 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36417 this.textSizeEl = Roo.DomHelper.append(document.body, {
36418 tag: "pre", cls: "x-form-grow-sizer"
36420 if(this.preventScrollbars){
36421 this.el.setStyle("overflow", "hidden");
36423 this.el.setHeight(this.growMin);
36427 onDestroy : function(){
36428 if(this.textSizeEl){
36429 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36431 Roo.form.TextArea.superclass.onDestroy.call(this);
36435 onKeyUp : function(e){
36436 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36442 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36443 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36445 autoSize : function(){
36446 if(!this.grow || !this.textSizeEl){
36450 var v = el.dom.value;
36451 var ts = this.textSizeEl;
36454 ts.appendChild(document.createTextNode(v));
36457 Roo.fly(ts).setWidth(this.el.getWidth());
36459 v = "  ";
36462 v = v.replace(/\n/g, '<p> </p>');
36464 v += " \n ";
36467 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36468 if(h != this.lastHeight){
36469 this.lastHeight = h;
36470 this.el.setHeight(h);
36471 this.fireEvent("autosize", this, h);
36476 * Ext JS Library 1.1.1
36477 * Copyright(c) 2006-2007, Ext JS, LLC.
36479 * Originally Released Under LGPL - original licence link has changed is not relivant.
36482 * <script type="text/javascript">
36487 * @class Roo.form.NumberField
36488 * @extends Roo.form.TextField
36489 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36491 * Creates a new NumberField
36492 * @param {Object} config Configuration options
36494 Roo.form.NumberField = function(config){
36495 Roo.form.NumberField.superclass.constructor.call(this, config);
36498 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36500 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36502 fieldClass: "x-form-field x-form-num-field",
36504 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36506 allowDecimals : true,
36508 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36510 decimalSeparator : ".",
36512 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36514 decimalPrecision : 2,
36516 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36518 allowNegative : true,
36520 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36522 minValue : Number.NEGATIVE_INFINITY,
36524 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36526 maxValue : Number.MAX_VALUE,
36528 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36530 minText : "The minimum value for this field is {0}",
36532 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36534 maxText : "The maximum value for this field is {0}",
36536 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36537 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36539 nanText : "{0} is not a valid number",
36542 initEvents : function(){
36543 Roo.form.NumberField.superclass.initEvents.call(this);
36544 var allowed = "0123456789";
36545 if(this.allowDecimals){
36546 allowed += this.decimalSeparator;
36548 if(this.allowNegative){
36551 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36552 var keyPress = function(e){
36553 var k = e.getKey();
36554 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36557 var c = e.getCharCode();
36558 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36562 this.el.on("keypress", keyPress, this);
36566 validateValue : function(value){
36567 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36570 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36573 var num = this.parseValue(value);
36575 this.markInvalid(String.format(this.nanText, value));
36578 if(num < this.minValue){
36579 this.markInvalid(String.format(this.minText, this.minValue));
36582 if(num > this.maxValue){
36583 this.markInvalid(String.format(this.maxText, this.maxValue));
36589 getValue : function(){
36590 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36594 parseValue : function(value){
36595 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36596 return isNaN(value) ? '' : value;
36600 fixPrecision : function(value){
36601 var nan = isNaN(value);
36602 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36603 return nan ? '' : value;
36605 return parseFloat(value).toFixed(this.decimalPrecision);
36608 setValue : function(v){
36609 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36613 decimalPrecisionFcn : function(v){
36614 return Math.floor(v);
36617 beforeBlur : function(){
36618 var v = this.parseValue(this.getRawValue());
36620 this.setValue(this.fixPrecision(v));
36625 * Ext JS Library 1.1.1
36626 * Copyright(c) 2006-2007, Ext JS, LLC.
36628 * Originally Released Under LGPL - original licence link has changed is not relivant.
36631 * <script type="text/javascript">
36635 * @class Roo.form.DateField
36636 * @extends Roo.form.TriggerField
36637 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36639 * Create a new DateField
36640 * @param {Object} config
36642 Roo.form.DateField = function(config){
36643 Roo.form.DateField.superclass.constructor.call(this, config);
36649 * Fires when a date is selected
36650 * @param {Roo.form.DateField} combo This combo box
36651 * @param {Date} date The date selected
36658 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36659 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36660 this.ddMatch = null;
36661 if(this.disabledDates){
36662 var dd = this.disabledDates;
36664 for(var i = 0; i < dd.length; i++){
36666 if(i != dd.length-1) re += "|";
36668 this.ddMatch = new RegExp(re + ")");
36672 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36674 * @cfg {String} format
36675 * The default date format string which can be overriden for localization support. The format must be
36676 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36680 * @cfg {String} altFormats
36681 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36682 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36684 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36686 * @cfg {Array} disabledDays
36687 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36689 disabledDays : null,
36691 * @cfg {String} disabledDaysText
36692 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36694 disabledDaysText : "Disabled",
36696 * @cfg {Array} disabledDates
36697 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36698 * expression so they are very powerful. Some examples:
36700 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36701 * <li>["03/08", "09/16"] would disable those days for every year</li>
36702 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36703 * <li>["03/../2006"] would disable every day in March 2006</li>
36704 * <li>["^03"] would disable every day in every March</li>
36706 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36707 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36709 disabledDates : null,
36711 * @cfg {String} disabledDatesText
36712 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36714 disabledDatesText : "Disabled",
36716 * @cfg {Date/String} minValue
36717 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36718 * valid format (defaults to null).
36722 * @cfg {Date/String} maxValue
36723 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36724 * valid format (defaults to null).
36728 * @cfg {String} minText
36729 * The error text to display when the date in the cell is before minValue (defaults to
36730 * 'The date in this field must be after {minValue}').
36732 minText : "The date in this field must be equal to or after {0}",
36734 * @cfg {String} maxText
36735 * The error text to display when the date in the cell is after maxValue (defaults to
36736 * 'The date in this field must be before {maxValue}').
36738 maxText : "The date in this field must be equal to or before {0}",
36740 * @cfg {String} invalidText
36741 * The error text to display when the date in the field is invalid (defaults to
36742 * '{value} is not a valid date - it must be in the format {format}').
36744 invalidText : "{0} is not a valid date - it must be in the format {1}",
36746 * @cfg {String} triggerClass
36747 * An additional CSS class used to style the trigger button. The trigger will always get the
36748 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36749 * which displays a calendar icon).
36751 triggerClass : 'x-form-date-trigger',
36755 * @cfg {bool} useIso
36756 * if enabled, then the date field will use a hidden field to store the
36757 * real value as iso formated date. default (false)
36761 * @cfg {String/Object} autoCreate
36762 * A DomHelper element spec, or true for a default element spec (defaults to
36763 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36766 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36769 hiddenField: false,
36771 onRender : function(ct, position)
36773 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36775 this.el.dom.removeAttribute('name');
36776 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36778 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36779 // prevent input submission
36780 this.hiddenName = this.name;
36787 validateValue : function(value)
36789 value = this.formatDate(value);
36790 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36793 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36796 var svalue = value;
36797 value = this.parseDate(value);
36799 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36802 var time = value.getTime();
36803 if(this.minValue && time < this.minValue.getTime()){
36804 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36807 if(this.maxValue && time > this.maxValue.getTime()){
36808 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36811 if(this.disabledDays){
36812 var day = value.getDay();
36813 for(var i = 0; i < this.disabledDays.length; i++) {
36814 if(day === this.disabledDays[i]){
36815 this.markInvalid(this.disabledDaysText);
36820 var fvalue = this.formatDate(value);
36821 if(this.ddMatch && this.ddMatch.test(fvalue)){
36822 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36829 // Provides logic to override the default TriggerField.validateBlur which just returns true
36830 validateBlur : function(){
36831 return !this.menu || !this.menu.isVisible();
36835 * Returns the current date value of the date field.
36836 * @return {Date} The date value
36838 getValue : function(){
36840 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36844 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36845 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36846 * (the default format used is "m/d/y").
36849 //All of these calls set the same date value (May 4, 2006)
36851 //Pass a date object:
36852 var dt = new Date('5/4/06');
36853 dateField.setValue(dt);
36855 //Pass a date string (default format):
36856 dateField.setValue('5/4/06');
36858 //Pass a date string (custom format):
36859 dateField.format = 'Y-m-d';
36860 dateField.setValue('2006-5-4');
36862 * @param {String/Date} date The date or valid date string
36864 setValue : function(date){
36865 if (this.hiddenField) {
36866 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36868 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36872 parseDate : function(value){
36873 if(!value || value instanceof Date){
36876 var v = Date.parseDate(value, this.format);
36877 if(!v && this.altFormats){
36878 if(!this.altFormatsArray){
36879 this.altFormatsArray = this.altFormats.split("|");
36881 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36882 v = Date.parseDate(value, this.altFormatsArray[i]);
36889 formatDate : function(date, fmt){
36890 return (!date || !(date instanceof Date)) ?
36891 date : date.dateFormat(fmt || this.format);
36896 select: function(m, d){
36898 this.fireEvent('select', this, d);
36900 show : function(){ // retain focus styling
36904 this.focus.defer(10, this);
36905 var ml = this.menuListeners;
36906 this.menu.un("select", ml.select, this);
36907 this.menu.un("show", ml.show, this);
36908 this.menu.un("hide", ml.hide, this);
36913 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36914 onTriggerClick : function(){
36918 if(this.menu == null){
36919 this.menu = new Roo.menu.DateMenu();
36921 Roo.apply(this.menu.picker, {
36922 showClear: this.allowBlank,
36923 minDate : this.minValue,
36924 maxDate : this.maxValue,
36925 disabledDatesRE : this.ddMatch,
36926 disabledDatesText : this.disabledDatesText,
36927 disabledDays : this.disabledDays,
36928 disabledDaysText : this.disabledDaysText,
36929 format : this.format,
36930 minText : String.format(this.minText, this.formatDate(this.minValue)),
36931 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36933 this.menu.on(Roo.apply({}, this.menuListeners, {
36936 this.menu.picker.setValue(this.getValue() || new Date());
36937 this.menu.show(this.el, "tl-bl?");
36940 beforeBlur : function(){
36941 var v = this.parseDate(this.getRawValue());
36947 /** @cfg {Boolean} grow @hide */
36948 /** @cfg {Number} growMin @hide */
36949 /** @cfg {Number} growMax @hide */
36956 * Ext JS Library 1.1.1
36957 * Copyright(c) 2006-2007, Ext JS, LLC.
36959 * Originally Released Under LGPL - original licence link has changed is not relivant.
36962 * <script type="text/javascript">
36967 * @class Roo.form.ComboBox
36968 * @extends Roo.form.TriggerField
36969 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36971 * Create a new ComboBox.
36972 * @param {Object} config Configuration options
36974 Roo.form.ComboBox = function(config){
36975 Roo.form.ComboBox.superclass.constructor.call(this, config);
36979 * Fires when the dropdown list is expanded
36980 * @param {Roo.form.ComboBox} combo This combo box
36985 * Fires when the dropdown list is collapsed
36986 * @param {Roo.form.ComboBox} combo This combo box
36990 * @event beforeselect
36991 * Fires before a list item is selected. Return false to cancel the selection.
36992 * @param {Roo.form.ComboBox} combo This combo box
36993 * @param {Roo.data.Record} record The data record returned from the underlying store
36994 * @param {Number} index The index of the selected item in the dropdown list
36996 'beforeselect' : true,
36999 * Fires when a list item is selected
37000 * @param {Roo.form.ComboBox} combo This combo box
37001 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37002 * @param {Number} index The index of the selected item in the dropdown list
37006 * @event beforequery
37007 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37008 * The event object passed has these properties:
37009 * @param {Roo.form.ComboBox} combo This combo box
37010 * @param {String} query The query
37011 * @param {Boolean} forceAll true to force "all" query
37012 * @param {Boolean} cancel true to cancel the query
37013 * @param {Object} e The query event object
37015 'beforequery': true,
37018 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37019 * @param {Roo.form.ComboBox} combo This combo box
37024 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37025 * @param {Roo.form.ComboBox} combo This combo box
37026 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37032 if(this.transform){
37033 this.allowDomMove = false;
37034 var s = Roo.getDom(this.transform);
37035 if(!this.hiddenName){
37036 this.hiddenName = s.name;
37039 this.mode = 'local';
37040 var d = [], opts = s.options;
37041 for(var i = 0, len = opts.length;i < len; i++){
37043 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37045 this.value = value;
37047 d.push([value, o.text]);
37049 this.store = new Roo.data.SimpleStore({
37051 fields: ['value', 'text'],
37054 this.valueField = 'value';
37055 this.displayField = 'text';
37057 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37058 if(!this.lazyRender){
37059 this.target = true;
37060 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37061 s.parentNode.removeChild(s); // remove it
37062 this.render(this.el.parentNode);
37064 s.parentNode.removeChild(s); // remove it
37069 this.store = Roo.factory(this.store, Roo.data);
37072 this.selectedIndex = -1;
37073 if(this.mode == 'local'){
37074 if(config.queryDelay === undefined){
37075 this.queryDelay = 10;
37077 if(config.minChars === undefined){
37083 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37085 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37088 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37089 * rendering into an Roo.Editor, defaults to false)
37092 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37093 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37096 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37099 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37100 * the dropdown list (defaults to undefined, with no header element)
37104 * @cfg {String/Roo.Template} tpl The template to use to render the output
37108 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37110 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37112 listWidth: undefined,
37114 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37115 * mode = 'remote' or 'text' if mode = 'local')
37117 displayField: undefined,
37119 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37120 * mode = 'remote' or 'value' if mode = 'local').
37121 * Note: use of a valueField requires the user make a selection
37122 * in order for a value to be mapped.
37124 valueField: undefined,
37126 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37127 * field's data value (defaults to the underlying DOM element's name)
37129 hiddenName: undefined,
37131 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37135 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37137 selectedClass: 'x-combo-selected',
37139 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37140 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37141 * which displays a downward arrow icon).
37143 triggerClass : 'x-form-arrow-trigger',
37145 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37149 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37150 * anchor positions (defaults to 'tl-bl')
37152 listAlign: 'tl-bl?',
37154 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37158 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37159 * query specified by the allQuery config option (defaults to 'query')
37161 triggerAction: 'query',
37163 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37164 * (defaults to 4, does not apply if editable = false)
37168 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37169 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37173 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37174 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37178 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37179 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37183 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37184 * when editable = true (defaults to false)
37186 selectOnFocus:false,
37188 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37190 queryParam: 'query',
37192 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37193 * when mode = 'remote' (defaults to 'Loading...')
37195 loadingText: 'Loading...',
37197 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37201 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37205 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37206 * traditional select (defaults to true)
37210 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37214 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37218 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37219 * listWidth has a higher value)
37223 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37224 * allow the user to set arbitrary text into the field (defaults to false)
37226 forceSelection:false,
37228 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37229 * if typeAhead = true (defaults to 250)
37231 typeAheadDelay : 250,
37233 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37234 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37236 valueNotFoundText : undefined,
37238 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37240 blockFocus : false,
37243 * @cfg {Boolean} disableClear Disable showing of clear button.
37245 disableClear : false,
37247 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37249 alwaysQuery : false,
37257 onRender : function(ct, position){
37258 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37259 if(this.hiddenName){
37260 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37262 this.hiddenField.value =
37263 this.hiddenValue !== undefined ? this.hiddenValue :
37264 this.value !== undefined ? this.value : '';
37266 // prevent input submission
37267 this.el.dom.removeAttribute('name');
37270 this.el.dom.setAttribute('autocomplete', 'off');
37273 var cls = 'x-combo-list';
37275 this.list = new Roo.Layer({
37276 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37279 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37280 this.list.setWidth(lw);
37281 this.list.swallowEvent('mousewheel');
37282 this.assetHeight = 0;
37285 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37286 this.assetHeight += this.header.getHeight();
37289 this.innerList = this.list.createChild({cls:cls+'-inner'});
37290 this.innerList.on('mouseover', this.onViewOver, this);
37291 this.innerList.on('mousemove', this.onViewMove, this);
37292 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37294 if(this.allowBlank && !this.pageSize && !this.disableClear){
37295 this.footer = this.list.createChild({cls:cls+'-ft'});
37296 this.pageTb = new Roo.Toolbar(this.footer);
37300 this.footer = this.list.createChild({cls:cls+'-ft'});
37301 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37302 {pageSize: this.pageSize});
37306 if (this.pageTb && this.allowBlank && !this.disableClear) {
37308 this.pageTb.add(new Roo.Toolbar.Fill(), {
37309 cls: 'x-btn-icon x-btn-clear',
37311 handler: function()
37314 _this.clearValue();
37315 _this.onSelect(false, -1);
37320 this.assetHeight += this.footer.getHeight();
37325 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37328 this.view = new Roo.View(this.innerList, this.tpl, {
37329 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37332 this.view.on('click', this.onViewClick, this);
37334 this.store.on('beforeload', this.onBeforeLoad, this);
37335 this.store.on('load', this.onLoad, this);
37336 this.store.on('loadexception', this.collapse, this);
37338 if(this.resizable){
37339 this.resizer = new Roo.Resizable(this.list, {
37340 pinned:true, handles:'se'
37342 this.resizer.on('resize', function(r, w, h){
37343 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37344 this.listWidth = w;
37345 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37346 this.restrictHeight();
37348 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37350 if(!this.editable){
37351 this.editable = true;
37352 this.setEditable(false);
37356 if (typeof(this.events.add.listeners) != 'undefined') {
37358 this.addicon = this.wrap.createChild(
37359 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37361 this.addicon.on('click', function(e) {
37362 this.fireEvent('add', this);
37365 if (typeof(this.events.edit.listeners) != 'undefined') {
37367 this.editicon = this.wrap.createChild(
37368 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37369 if (this.addicon) {
37370 this.editicon.setStyle('margin-left', '40px');
37372 this.editicon.on('click', function(e) {
37374 // we fire even if inothing is selected..
37375 this.fireEvent('edit', this, this.lastData );
37385 initEvents : function(){
37386 Roo.form.ComboBox.superclass.initEvents.call(this);
37388 this.keyNav = new Roo.KeyNav(this.el, {
37389 "up" : function(e){
37390 this.inKeyMode = true;
37394 "down" : function(e){
37395 if(!this.isExpanded()){
37396 this.onTriggerClick();
37398 this.inKeyMode = true;
37403 "enter" : function(e){
37404 this.onViewClick();
37408 "esc" : function(e){
37412 "tab" : function(e){
37413 this.onViewClick(false);
37419 doRelay : function(foo, bar, hname){
37420 if(hname == 'down' || this.scope.isExpanded()){
37421 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37428 this.queryDelay = Math.max(this.queryDelay || 10,
37429 this.mode == 'local' ? 10 : 250);
37430 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37431 if(this.typeAhead){
37432 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37434 if(this.editable !== false){
37435 this.el.on("keyup", this.onKeyUp, this);
37437 if(this.forceSelection){
37438 this.on('blur', this.doForce, this);
37442 onDestroy : function(){
37444 this.view.setStore(null);
37445 this.view.el.removeAllListeners();
37446 this.view.el.remove();
37447 this.view.purgeListeners();
37450 this.list.destroy();
37453 this.store.un('beforeload', this.onBeforeLoad, this);
37454 this.store.un('load', this.onLoad, this);
37455 this.store.un('loadexception', this.collapse, this);
37457 Roo.form.ComboBox.superclass.onDestroy.call(this);
37461 fireKey : function(e){
37462 if(e.isNavKeyPress() && !this.list.isVisible()){
37463 this.fireEvent("specialkey", this, e);
37468 onResize: function(w, h){
37469 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37471 if(typeof w != 'number'){
37472 // we do not handle it!?!?
37475 var tw = this.trigger.getWidth();
37476 tw += this.addicon ? this.addicon.getWidth() : 0;
37477 tw += this.editicon ? this.editicon.getWidth() : 0;
37479 this.el.setWidth( this.adjustWidth('input', x));
37481 this.trigger.setStyle('left', x+'px');
37483 if(this.list && this.listWidth === undefined){
37484 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37485 this.list.setWidth(lw);
37486 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37494 * Allow or prevent the user from directly editing the field text. If false is passed,
37495 * the user will only be able to select from the items defined in the dropdown list. This method
37496 * is the runtime equivalent of setting the 'editable' config option at config time.
37497 * @param {Boolean} value True to allow the user to directly edit the field text
37499 setEditable : function(value){
37500 if(value == this.editable){
37503 this.editable = value;
37505 this.el.dom.setAttribute('readOnly', true);
37506 this.el.on('mousedown', this.onTriggerClick, this);
37507 this.el.addClass('x-combo-noedit');
37509 this.el.dom.setAttribute('readOnly', false);
37510 this.el.un('mousedown', this.onTriggerClick, this);
37511 this.el.removeClass('x-combo-noedit');
37516 onBeforeLoad : function(){
37517 if(!this.hasFocus){
37520 this.innerList.update(this.loadingText ?
37521 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37522 this.restrictHeight();
37523 this.selectedIndex = -1;
37527 onLoad : function(){
37528 if(!this.hasFocus){
37531 if(this.store.getCount() > 0){
37533 this.restrictHeight();
37534 if(this.lastQuery == this.allQuery){
37536 this.el.dom.select();
37538 if(!this.selectByValue(this.value, true)){
37539 this.select(0, true);
37543 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37544 this.taTask.delay(this.typeAheadDelay);
37548 this.onEmptyResults();
37554 onTypeAhead : function(){
37555 if(this.store.getCount() > 0){
37556 var r = this.store.getAt(0);
37557 var newValue = r.data[this.displayField];
37558 var len = newValue.length;
37559 var selStart = this.getRawValue().length;
37560 if(selStart != len){
37561 this.setRawValue(newValue);
37562 this.selectText(selStart, newValue.length);
37568 onSelect : function(record, index){
37569 if(this.fireEvent('beforeselect', this, record, index) !== false){
37570 this.setFromData(index > -1 ? record.data : false);
37572 this.fireEvent('select', this, record, index);
37577 * Returns the currently selected field value or empty string if no value is set.
37578 * @return {String} value The selected value
37580 getValue : function(){
37581 if(this.valueField){
37582 return typeof this.value != 'undefined' ? this.value : '';
37584 return Roo.form.ComboBox.superclass.getValue.call(this);
37589 * Clears any text/value currently set in the field
37591 clearValue : function(){
37592 if(this.hiddenField){
37593 this.hiddenField.value = '';
37596 this.setRawValue('');
37597 this.lastSelectionText = '';
37598 this.applyEmptyText();
37602 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37603 * will be displayed in the field. If the value does not match the data value of an existing item,
37604 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37605 * Otherwise the field will be blank (although the value will still be set).
37606 * @param {String} value The value to match
37608 setValue : function(v){
37610 if(this.valueField){
37611 var r = this.findRecord(this.valueField, v);
37613 text = r.data[this.displayField];
37614 }else if(this.valueNotFoundText !== undefined){
37615 text = this.valueNotFoundText;
37618 this.lastSelectionText = text;
37619 if(this.hiddenField){
37620 this.hiddenField.value = v;
37622 Roo.form.ComboBox.superclass.setValue.call(this, text);
37626 * @property {Object} the last set data for the element
37631 * Sets the value of the field based on a object which is related to the record format for the store.
37632 * @param {Object} value the value to set as. or false on reset?
37634 setFromData : function(o){
37635 var dv = ''; // display value
37636 var vv = ''; // value value..
37638 if (this.displayField) {
37639 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37641 // this is an error condition!!!
37642 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37645 if(this.valueField){
37646 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37648 if(this.hiddenField){
37649 this.hiddenField.value = vv;
37651 this.lastSelectionText = dv;
37652 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37656 // no hidden field.. - we store the value in 'value', but still display
37657 // display field!!!!
37658 this.lastSelectionText = dv;
37659 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37665 reset : function(){
37666 // overridden so that last data is reset..
37667 this.setValue(this.originalValue);
37668 this.clearInvalid();
37669 this.lastData = false;
37672 findRecord : function(prop, value){
37674 if(this.store.getCount() > 0){
37675 this.store.each(function(r){
37676 if(r.data[prop] == value){
37686 onViewMove : function(e, t){
37687 this.inKeyMode = false;
37691 onViewOver : function(e, t){
37692 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37695 var item = this.view.findItemFromChild(t);
37697 var index = this.view.indexOf(item);
37698 this.select(index, false);
37703 onViewClick : function(doFocus){
37704 var index = this.view.getSelectedIndexes()[0];
37705 var r = this.store.getAt(index);
37707 this.onSelect(r, index);
37709 if(doFocus !== false && !this.blockFocus){
37715 restrictHeight : function(){
37716 this.innerList.dom.style.height = '';
37717 var inner = this.innerList.dom;
37718 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37719 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37720 this.list.beginUpdate();
37721 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37722 this.list.alignTo(this.el, this.listAlign);
37723 this.list.endUpdate();
37727 onEmptyResults : function(){
37732 * Returns true if the dropdown list is expanded, else false.
37734 isExpanded : function(){
37735 return this.list.isVisible();
37739 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37740 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37741 * @param {String} value The data value of the item to select
37742 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37743 * selected item if it is not currently in view (defaults to true)
37744 * @return {Boolean} True if the value matched an item in the list, else false
37746 selectByValue : function(v, scrollIntoView){
37747 if(v !== undefined && v !== null){
37748 var r = this.findRecord(this.valueField || this.displayField, v);
37750 this.select(this.store.indexOf(r), scrollIntoView);
37758 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37759 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37760 * @param {Number} index The zero-based index of the list item to select
37761 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37762 * selected item if it is not currently in view (defaults to true)
37764 select : function(index, scrollIntoView){
37765 this.selectedIndex = index;
37766 this.view.select(index);
37767 if(scrollIntoView !== false){
37768 var el = this.view.getNode(index);
37770 this.innerList.scrollChildIntoView(el, false);
37776 selectNext : function(){
37777 var ct = this.store.getCount();
37779 if(this.selectedIndex == -1){
37781 }else if(this.selectedIndex < ct-1){
37782 this.select(this.selectedIndex+1);
37788 selectPrev : function(){
37789 var ct = this.store.getCount();
37791 if(this.selectedIndex == -1){
37793 }else if(this.selectedIndex != 0){
37794 this.select(this.selectedIndex-1);
37800 onKeyUp : function(e){
37801 if(this.editable !== false && !e.isSpecialKey()){
37802 this.lastKey = e.getKey();
37803 this.dqTask.delay(this.queryDelay);
37808 validateBlur : function(){
37809 return !this.list || !this.list.isVisible();
37813 initQuery : function(){
37814 this.doQuery(this.getRawValue());
37818 doForce : function(){
37819 if(this.el.dom.value.length > 0){
37820 this.el.dom.value =
37821 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37822 this.applyEmptyText();
37827 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37828 * query allowing the query action to be canceled if needed.
37829 * @param {String} query The SQL query to execute
37830 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37831 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37832 * saved in the current store (defaults to false)
37834 doQuery : function(q, forceAll){
37835 if(q === undefined || q === null){
37840 forceAll: forceAll,
37844 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37848 forceAll = qe.forceAll;
37849 if(forceAll === true || (q.length >= this.minChars)){
37850 if(this.lastQuery != q || this.alwaysQuery){
37851 this.lastQuery = q;
37852 if(this.mode == 'local'){
37853 this.selectedIndex = -1;
37855 this.store.clearFilter();
37857 this.store.filter(this.displayField, q);
37861 this.store.baseParams[this.queryParam] = q;
37863 params: this.getParams(q)
37868 this.selectedIndex = -1;
37875 getParams : function(q){
37877 //p[this.queryParam] = q;
37880 p.limit = this.pageSize;
37886 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37888 collapse : function(){
37889 if(!this.isExpanded()){
37893 Roo.get(document).un('mousedown', this.collapseIf, this);
37894 Roo.get(document).un('mousewheel', this.collapseIf, this);
37895 if (!this.editable) {
37896 Roo.get(document).un('keydown', this.listKeyPress, this);
37898 this.fireEvent('collapse', this);
37902 collapseIf : function(e){
37903 if(!e.within(this.wrap) && !e.within(this.list)){
37909 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37911 expand : function(){
37912 if(this.isExpanded() || !this.hasFocus){
37915 this.list.alignTo(this.el, this.listAlign);
37917 Roo.get(document).on('mousedown', this.collapseIf, this);
37918 Roo.get(document).on('mousewheel', this.collapseIf, this);
37919 if (!this.editable) {
37920 Roo.get(document).on('keydown', this.listKeyPress, this);
37923 this.fireEvent('expand', this);
37927 // Implements the default empty TriggerField.onTriggerClick function
37928 onTriggerClick : function(){
37932 if(this.isExpanded()){
37934 if (!this.blockFocus) {
37939 this.hasFocus = true;
37940 if(this.triggerAction == 'all') {
37941 this.doQuery(this.allQuery, true);
37943 this.doQuery(this.getRawValue());
37945 if (!this.blockFocus) {
37950 listKeyPress : function(e)
37952 //Roo.log('listkeypress');
37953 // scroll to first matching element based on key pres..
37954 if (e.isSpecialKey()) {
37957 var k = String.fromCharCode(e.getKey()).toUpperCase();
37960 var csel = this.view.getSelectedNodes();
37961 var cselitem = false;
37963 var ix = this.view.indexOf(csel[0]);
37964 cselitem = this.store.getAt(ix);
37965 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
37971 this.store.each(function(v) {
37973 // start at existing selection.
37974 if (cselitem.id == v.id) {
37980 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
37981 match = this.store.indexOf(v);
37986 if (match === false) {
37987 return true; // no more action?
37990 this.view.select(match);
37991 var sn = Roo.get(this.view.getSelectedNodes()[0])
37992 sn.scrollIntoView(sn.dom.parentNode, false);
37996 * @cfg {Boolean} grow
38000 * @cfg {Number} growMin
38004 * @cfg {Number} growMax
38013 * Ext JS Library 1.1.1
38014 * Copyright(c) 2006-2007, Ext JS, LLC.
38016 * Originally Released Under LGPL - original licence link has changed is not relivant.
38019 * <script type="text/javascript">
38022 * @class Roo.form.Checkbox
38023 * @extends Roo.form.Field
38024 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38026 * Creates a new Checkbox
38027 * @param {Object} config Configuration options
38029 Roo.form.Checkbox = function(config){
38030 Roo.form.Checkbox.superclass.constructor.call(this, config);
38034 * Fires when the checkbox is checked or unchecked.
38035 * @param {Roo.form.Checkbox} this This checkbox
38036 * @param {Boolean} checked The new checked value
38042 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38044 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38046 focusClass : undefined,
38048 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38050 fieldClass: "x-form-field",
38052 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38056 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38057 * {tag: "input", type: "checkbox", autocomplete: "off"})
38059 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38061 * @cfg {String} boxLabel The text that appears beside the checkbox
38065 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38069 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38071 valueOff: '0', // value when not checked..
38073 actionMode : 'viewEl',
38076 itemCls : 'x-menu-check-item x-form-item',
38077 groupClass : 'x-menu-group-item',
38078 inputType : 'hidden',
38081 inSetChecked: false, // check that we are not calling self...
38083 inputElement: false, // real input element?
38084 basedOn: false, // ????
38086 isFormField: true, // not sure where this is needed!!!!
38088 onResize : function(){
38089 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38090 if(!this.boxLabel){
38091 this.el.alignTo(this.wrap, 'c-c');
38095 initEvents : function(){
38096 Roo.form.Checkbox.superclass.initEvents.call(this);
38097 this.el.on("click", this.onClick, this);
38098 this.el.on("change", this.onClick, this);
38102 getResizeEl : function(){
38106 getPositionEl : function(){
38111 onRender : function(ct, position){
38112 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38114 if(this.inputValue !== undefined){
38115 this.el.dom.value = this.inputValue;
38118 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38119 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38120 var viewEl = this.wrap.createChild({
38121 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38122 this.viewEl = viewEl;
38123 this.wrap.on('click', this.onClick, this);
38125 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38126 this.el.on('propertychange', this.setFromHidden, this); //ie
38131 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38132 // viewEl.on('click', this.onClick, this);
38134 //if(this.checked){
38135 this.setChecked(this.checked);
38137 //this.checked = this.el.dom;
38143 initValue : Roo.emptyFn,
38146 * Returns the checked state of the checkbox.
38147 * @return {Boolean} True if checked, else false
38149 getValue : function(){
38151 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38153 return this.valueOff;
38158 onClick : function(){
38159 this.setChecked(!this.checked);
38161 //if(this.el.dom.checked != this.checked){
38162 // this.setValue(this.el.dom.checked);
38167 * Sets the checked state of the checkbox.
38168 * On is always based on a string comparison between inputValue and the param.
38169 * @param {Boolean/String} value - the value to set
38170 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38172 setValue : function(v,suppressEvent){
38175 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38176 //if(this.el && this.el.dom){
38177 // this.el.dom.checked = this.checked;
38178 // this.el.dom.defaultChecked = this.checked;
38180 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38181 //this.fireEvent("check", this, this.checked);
38184 setChecked : function(state,suppressEvent)
38186 if (this.inSetChecked) {
38187 this.checked = state;
38193 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38195 this.checked = state;
38196 if(suppressEvent !== true){
38197 this.fireEvent('check', this, state);
38199 this.inSetChecked = true;
38200 this.el.dom.value = state ? this.inputValue : this.valueOff;
38201 this.inSetChecked = false;
38204 // handle setting of hidden value by some other method!!?!?
38205 setFromHidden: function()
38210 //console.log("SET FROM HIDDEN");
38211 //alert('setFrom hidden');
38212 this.setValue(this.el.dom.value);
38215 onDestroy : function()
38218 Roo.get(this.viewEl).remove();
38221 Roo.form.Checkbox.superclass.onDestroy.call(this);
38226 * Ext JS Library 1.1.1
38227 * Copyright(c) 2006-2007, Ext JS, LLC.
38229 * Originally Released Under LGPL - original licence link has changed is not relivant.
38232 * <script type="text/javascript">
38236 * @class Roo.form.Radio
38237 * @extends Roo.form.Checkbox
38238 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38239 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38241 * Creates a new Radio
38242 * @param {Object} config Configuration options
38244 Roo.form.Radio = function(){
38245 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38247 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38248 inputType: 'radio',
38251 * If this radio is part of a group, it will return the selected value
38254 getGroupValue : function(){
38255 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38257 });//<script type="text/javascript">
38260 * Ext JS Library 1.1.1
38261 * Copyright(c) 2006-2007, Ext JS, LLC.
38262 * licensing@extjs.com
38264 * http://www.extjs.com/license
38270 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38271 * - IE ? - no idea how much works there.
38279 * @class Ext.form.HtmlEditor
38280 * @extends Ext.form.Field
38281 * Provides a lightweight HTML Editor component.
38282 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38284 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38285 * supported by this editor.</b><br/><br/>
38286 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38287 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38289 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38291 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38295 * @cfg {String} createLinkText The default text for the create link prompt
38297 createLinkText : 'Please enter the URL for the link:',
38299 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38301 defaultLinkValue : 'http:/'+'/',
38307 // private properties
38308 validationEvent : false,
38310 initialized : false,
38312 sourceEditMode : false,
38313 onFocus : Roo.emptyFn,
38315 hideMode:'offsets',
38316 defaultAutoCreate : {
38318 style:"width:500px;height:300px;",
38319 autocomplete: "off"
38323 initComponent : function(){
38326 * @event initialize
38327 * Fires when the editor is fully initialized (including the iframe)
38328 * @param {HtmlEditor} this
38333 * Fires when the editor is first receives the focus. Any insertion must wait
38334 * until after this event.
38335 * @param {HtmlEditor} this
38339 * @event beforesync
38340 * Fires before the textarea is updated with content from the editor iframe. Return false
38341 * to cancel the sync.
38342 * @param {HtmlEditor} this
38343 * @param {String} html
38347 * @event beforepush
38348 * Fires before the iframe editor is updated with content from the textarea. Return false
38349 * to cancel the push.
38350 * @param {HtmlEditor} this
38351 * @param {String} html
38356 * Fires when the textarea is updated with content from the editor iframe.
38357 * @param {HtmlEditor} this
38358 * @param {String} html
38363 * Fires when the iframe editor is updated with content from the textarea.
38364 * @param {HtmlEditor} this
38365 * @param {String} html
38369 * @event editmodechange
38370 * Fires when the editor switches edit modes
38371 * @param {HtmlEditor} this
38372 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38374 editmodechange: true,
38376 * @event editorevent
38377 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38378 * @param {HtmlEditor} this
38385 * Protected method that will not generally be called directly. It
38386 * is called when the editor creates its toolbar. Override this method if you need to
38387 * add custom toolbar buttons.
38388 * @param {HtmlEditor} editor
38390 createToolbar : function(editor){
38391 if (!editor.toolbars || !editor.toolbars.length) {
38392 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38395 for (var i =0 ; i < editor.toolbars.length;i++) {
38396 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38397 editor.toolbars[i].init(editor);
38404 * Protected method that will not generally be called directly. It
38405 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38406 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38408 getDocMarkup : function(){
38409 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38413 onRender : function(ct, position){
38414 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38415 this.el.dom.style.border = '0 none';
38416 this.el.dom.setAttribute('tabIndex', -1);
38417 this.el.addClass('x-hidden');
38418 if(Roo.isIE){ // fix IE 1px bogus margin
38419 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38421 this.wrap = this.el.wrap({
38422 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38425 this.frameId = Roo.id();
38426 this.createToolbar(this);
38433 var iframe = this.wrap.createChild({
38436 name: this.frameId,
38437 frameBorder : 'no',
38438 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38441 // console.log(iframe);
38442 //this.wrap.dom.appendChild(iframe);
38444 this.iframe = iframe.dom;
38446 this.assignDocWin();
38448 this.doc.designMode = 'on';
38451 this.doc.write(this.getDocMarkup());
38455 var task = { // must defer to wait for browser to be ready
38457 //console.log("run task?" + this.doc.readyState);
38458 this.assignDocWin();
38459 if(this.doc.body || this.doc.readyState == 'complete'){
38461 this.doc.designMode="on";
38465 Roo.TaskMgr.stop(task);
38466 this.initEditor.defer(10, this);
38473 Roo.TaskMgr.start(task);
38476 this.setSize(this.el.getSize());
38481 onResize : function(w, h){
38482 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38483 if(this.el && this.iframe){
38484 if(typeof w == 'number'){
38485 var aw = w - this.wrap.getFrameWidth('lr');
38486 this.el.setWidth(this.adjustWidth('textarea', aw));
38487 this.iframe.style.width = aw + 'px';
38489 if(typeof h == 'number'){
38491 for (var i =0; i < this.toolbars.length;i++) {
38492 // fixme - ask toolbars for heights?
38493 tbh += this.toolbars[i].tb.el.getHeight();
38499 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38500 this.el.setHeight(this.adjustWidth('textarea', ah));
38501 this.iframe.style.height = ah + 'px';
38503 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38510 * Toggles the editor between standard and source edit mode.
38511 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38513 toggleSourceEdit : function(sourceEditMode){
38515 this.sourceEditMode = sourceEditMode === true;
38517 if(this.sourceEditMode){
38520 this.iframe.className = 'x-hidden';
38521 this.el.removeClass('x-hidden');
38522 this.el.dom.removeAttribute('tabIndex');
38527 this.iframe.className = '';
38528 this.el.addClass('x-hidden');
38529 this.el.dom.setAttribute('tabIndex', -1);
38532 this.setSize(this.wrap.getSize());
38533 this.fireEvent('editmodechange', this, this.sourceEditMode);
38536 // private used internally
38537 createLink : function(){
38538 var url = prompt(this.createLinkText, this.defaultLinkValue);
38539 if(url && url != 'http:/'+'/'){
38540 this.relayCmd('createlink', url);
38544 // private (for BoxComponent)
38545 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38547 // private (for BoxComponent)
38548 getResizeEl : function(){
38552 // private (for BoxComponent)
38553 getPositionEl : function(){
38558 initEvents : function(){
38559 this.originalValue = this.getValue();
38563 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38566 markInvalid : Roo.emptyFn,
38568 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38571 clearInvalid : Roo.emptyFn,
38573 setValue : function(v){
38574 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38579 * Protected method that will not generally be called directly. If you need/want
38580 * custom HTML cleanup, this is the method you should override.
38581 * @param {String} html The HTML to be cleaned
38582 * return {String} The cleaned HTML
38584 cleanHtml : function(html){
38585 html = String(html);
38586 if(html.length > 5){
38587 if(Roo.isSafari){ // strip safari nonsense
38588 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38591 if(html == ' '){
38598 * Protected method that will not generally be called directly. Syncs the contents
38599 * of the editor iframe with the textarea.
38601 syncValue : function(){
38602 if(this.initialized){
38603 var bd = (this.doc.body || this.doc.documentElement);
38604 var html = bd.innerHTML;
38606 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38607 var m = bs.match(/text-align:(.*?);/i);
38609 html = '<div style="'+m[0]+'">' + html + '</div>';
38612 html = this.cleanHtml(html);
38613 if(this.fireEvent('beforesync', this, html) !== false){
38614 this.el.dom.value = html;
38615 this.fireEvent('sync', this, html);
38621 * Protected method that will not generally be called directly. Pushes the value of the textarea
38622 * into the iframe editor.
38624 pushValue : function(){
38625 if(this.initialized){
38626 var v = this.el.dom.value;
38630 if(this.fireEvent('beforepush', this, v) !== false){
38631 (this.doc.body || this.doc.documentElement).innerHTML = v;
38632 this.fireEvent('push', this, v);
38638 deferFocus : function(){
38639 this.focus.defer(10, this);
38643 focus : function(){
38644 if(this.win && !this.sourceEditMode){
38651 assignDocWin: function()
38653 var iframe = this.iframe;
38656 this.doc = iframe.contentWindow.document;
38657 this.win = iframe.contentWindow;
38659 if (!Roo.get(this.frameId)) {
38662 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38663 this.win = Roo.get(this.frameId).dom.contentWindow;
38668 initEditor : function(){
38669 //console.log("INIT EDITOR");
38670 this.assignDocWin();
38674 this.doc.designMode="on";
38676 this.doc.write(this.getDocMarkup());
38679 var dbody = (this.doc.body || this.doc.documentElement);
38680 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38681 // this copies styles from the containing element into thsi one..
38682 // not sure why we need all of this..
38683 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38684 ss['background-attachment'] = 'fixed'; // w3c
38685 dbody.bgProperties = 'fixed'; // ie
38686 Roo.DomHelper.applyStyles(dbody, ss);
38687 Roo.EventManager.on(this.doc, {
38688 'mousedown': this.onEditorEvent,
38689 'dblclick': this.onEditorEvent,
38690 'click': this.onEditorEvent,
38691 'keyup': this.onEditorEvent,
38696 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38698 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38699 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38701 this.initialized = true;
38703 this.fireEvent('initialize', this);
38708 onDestroy : function(){
38714 for (var i =0; i < this.toolbars.length;i++) {
38715 // fixme - ask toolbars for heights?
38716 this.toolbars[i].onDestroy();
38719 this.wrap.dom.innerHTML = '';
38720 this.wrap.remove();
38725 onFirstFocus : function(){
38727 this.assignDocWin();
38730 this.activated = true;
38731 for (var i =0; i < this.toolbars.length;i++) {
38732 this.toolbars[i].onFirstFocus();
38735 if(Roo.isGecko){ // prevent silly gecko errors
38737 var s = this.win.getSelection();
38738 if(!s.focusNode || s.focusNode.nodeType != 3){
38739 var r = s.getRangeAt(0);
38740 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38745 this.execCmd('useCSS', true);
38746 this.execCmd('styleWithCSS', false);
38749 this.fireEvent('activate', this);
38753 adjustFont: function(btn){
38754 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38755 //if(Roo.isSafari){ // safari
38758 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38759 if(Roo.isSafari){ // safari
38760 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38761 v = (v < 10) ? 10 : v;
38762 v = (v > 48) ? 48 : v;
38763 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38768 v = Math.max(1, v+adjust);
38770 this.execCmd('FontSize', v );
38773 onEditorEvent : function(e){
38774 this.fireEvent('editorevent', this, e);
38775 // this.updateToolbar();
38779 insertTag : function(tg)
38781 // could be a bit smarter... -> wrap the current selected tRoo..
38783 this.execCmd("formatblock", tg);
38787 insertText : function(txt)
38791 range = this.createRange();
38792 range.deleteContents();
38793 //alert(Sender.getAttribute('label'));
38795 range.insertNode(this.doc.createTextNode(txt));
38799 relayBtnCmd : function(btn){
38800 this.relayCmd(btn.cmd);
38804 * Executes a Midas editor command on the editor document and performs necessary focus and
38805 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38806 * @param {String} cmd The Midas command
38807 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38809 relayCmd : function(cmd, value){
38811 this.execCmd(cmd, value);
38812 this.fireEvent('editorevent', this);
38813 //this.updateToolbar();
38818 * Executes a Midas editor command directly on the editor document.
38819 * For visual commands, you should use {@link #relayCmd} instead.
38820 * <b>This should only be called after the editor is initialized.</b>
38821 * @param {String} cmd The Midas command
38822 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38824 execCmd : function(cmd, value){
38825 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38831 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38833 * @param {String} text
38835 insertAtCursor : function(text){
38836 if(!this.activated){
38841 var r = this.doc.selection.createRange();
38848 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38850 this.execCmd('InsertHTML', text);
38855 mozKeyPress : function(e){
38857 var c = e.getCharCode(), cmd;
38860 c = String.fromCharCode(c).toLowerCase();
38871 this.cleanUpPaste.defer(100, this);
38879 e.preventDefault();
38887 fixKeys : function(){ // load time branching for fastest keydown performance
38889 return function(e){
38890 var k = e.getKey(), r;
38893 r = this.doc.selection.createRange();
38896 r.pasteHTML('    ');
38903 r = this.doc.selection.createRange();
38905 var target = r.parentElement();
38906 if(!target || target.tagName.toLowerCase() != 'li'){
38908 r.pasteHTML('<br />');
38914 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38915 this.cleanUpPaste.defer(100, this);
38921 }else if(Roo.isOpera){
38922 return function(e){
38923 var k = e.getKey();
38927 this.execCmd('InsertHTML','    ');
38930 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38931 this.cleanUpPaste.defer(100, this);
38936 }else if(Roo.isSafari){
38937 return function(e){
38938 var k = e.getKey();
38942 this.execCmd('InsertText','\t');
38946 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38947 this.cleanUpPaste.defer(100, this);
38955 getAllAncestors: function()
38957 var p = this.getSelectedNode();
38960 a.push(p); // push blank onto stack..
38961 p = this.getParentElement();
38965 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38969 a.push(this.doc.body);
38973 lastSelNode : false,
38976 getSelection : function()
38978 this.assignDocWin();
38979 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38982 getSelectedNode: function()
38984 // this may only work on Gecko!!!
38986 // should we cache this!!!!
38991 var range = this.createRange(this.getSelection());
38994 var parent = range.parentElement();
38996 var testRange = range.duplicate();
38997 testRange.moveToElementText(parent);
38998 if (testRange.inRange(range)) {
39001 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39004 parent = parent.parentElement;
39010 var ar = range.endContainer.childNodes;
39012 ar = range.commonAncestorContainer.childNodes;
39013 //alert(ar.length);
39016 var other_nodes = [];
39017 var has_other_nodes = false;
39018 for (var i=0;i<ar.length;i++) {
39019 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39022 // fullly contained node.
39024 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39029 // probably selected..
39030 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39031 other_nodes.push(ar[i]);
39034 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39039 has_other_nodes = true;
39041 if (!nodes.length && other_nodes.length) {
39042 nodes= other_nodes;
39044 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39050 createRange: function(sel)
39052 // this has strange effects when using with
39053 // top toolbar - not sure if it's a great idea.
39054 //this.editor.contentWindow.focus();
39055 if (typeof sel != "undefined") {
39057 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39059 return this.doc.createRange();
39062 return this.doc.createRange();
39065 getParentElement: function()
39068 this.assignDocWin();
39069 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39071 var range = this.createRange(sel);
39074 var p = range.commonAncestorContainer;
39075 while (p.nodeType == 3) { // text node
39087 // BC Hacks - cause I cant work out what i was trying to do..
39088 rangeIntersectsNode : function(range, node)
39090 var nodeRange = node.ownerDocument.createRange();
39092 nodeRange.selectNode(node);
39095 nodeRange.selectNodeContents(node);
39098 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39099 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39101 rangeCompareNode : function(range, node) {
39102 var nodeRange = node.ownerDocument.createRange();
39104 nodeRange.selectNode(node);
39106 nodeRange.selectNodeContents(node);
39108 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39109 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39111 if (nodeIsBefore && !nodeIsAfter)
39113 if (!nodeIsBefore && nodeIsAfter)
39115 if (nodeIsBefore && nodeIsAfter)
39121 // private? - in a new class?
39122 cleanUpPaste : function()
39124 // cleans up the whole document..
39125 // console.log('cleanuppaste');
39126 this.cleanUpChildren(this.doc.body)
39130 cleanUpChildren : function (n)
39132 if (!n.childNodes.length) {
39135 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39136 this.cleanUpChild(n.childNodes[i]);
39143 cleanUpChild : function (node)
39145 //console.log(node);
39146 if (node.nodeName == "#text") {
39147 // clean up silly Windows -- stuff?
39150 if (node.nodeName == "#comment") {
39151 node.parentNode.removeChild(node);
39152 // clean up silly Windows -- stuff?
39156 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39158 node.parentNode.removeChild(node);
39162 if (!node.attributes || !node.attributes.length) {
39163 this.cleanUpChildren(node);
39167 function cleanAttr(n,v)
39170 if (v.match(/^\./) || v.match(/^\//)) {
39173 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39176 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39177 node.removeAttribute(n);
39181 function cleanStyle(n,v)
39183 if (v.match(/expression/)) { //XSS?? should we even bother..
39184 node.removeAttribute(n);
39189 var parts = v.split(/;/);
39190 Roo.each(parts, function(p) {
39191 p = p.replace(/\s+/g,'');
39195 var l = p.split(':').shift().replace(/\s+/g,'');
39197 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39198 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39199 node.removeAttribute(n);
39208 for (var i = node.attributes.length-1; i > -1 ; i--) {
39209 var a = node.attributes[i];
39211 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39212 node.removeAttribute(a.name);
39215 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39216 cleanAttr(a.name,a.value); // fixme..
39219 if (a.name == 'style') {
39220 cleanStyle(a.name,a.value);
39222 /// clean up MS crap..
39223 if (a.name == 'class') {
39224 if (a.value.match(/^Mso/)) {
39225 node.className = '';
39235 this.cleanUpChildren(node);
39241 // hide stuff that is not compatible
39255 * @event specialkey
39259 * @cfg {String} fieldClass @hide
39262 * @cfg {String} focusClass @hide
39265 * @cfg {String} autoCreate @hide
39268 * @cfg {String} inputType @hide
39271 * @cfg {String} invalidClass @hide
39274 * @cfg {String} invalidText @hide
39277 * @cfg {String} msgFx @hide
39280 * @cfg {String} validateOnBlur @hide
39284 Roo.form.HtmlEditor.white = [
39285 'area', 'br', 'img', 'input', 'hr', 'wbr',
39287 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39288 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39289 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39290 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39291 'table', 'ul', 'xmp',
39293 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39296 'dir', 'menu', 'ol', 'ul', 'dl',
39302 Roo.form.HtmlEditor.black = [
39303 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39305 'base', 'basefont', 'bgsound', 'blink', 'body',
39306 'frame', 'frameset', 'head', 'html', 'ilayer',
39307 'iframe', 'layer', 'link', 'meta', 'object',
39308 'script', 'style' ,'title', 'xml' // clean later..
39310 Roo.form.HtmlEditor.clean = [
39311 'script', 'style', 'title', 'xml'
39316 Roo.form.HtmlEditor.ablack = [
39320 Roo.form.HtmlEditor.aclean = [
39321 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39325 Roo.form.HtmlEditor.pwhite= [
39326 'http', 'https', 'mailto'
39329 Roo.form.HtmlEditor.cwhite= [
39334 // <script type="text/javascript">
39337 * Ext JS Library 1.1.1
39338 * Copyright(c) 2006-2007, Ext JS, LLC.
39344 * @class Roo.form.HtmlEditorToolbar1
39349 new Roo.form.HtmlEditor({
39352 new Roo.form.HtmlEditorToolbar1({
39353 disable : { fonts: 1 , format: 1, ..., ... , ...],
39359 * @cfg {Object} disable List of elements to disable..
39360 * @cfg {Array} btns List of additional buttons.
39364 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39367 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39370 Roo.apply(this, config);
39371 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39372 // dont call parent... till later.
39375 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39383 * @cfg {Object} disable List of toolbar elements to disable
39388 * @cfg {Array} fontFamilies An array of available font families
39406 // "á" , ?? a acute?
39411 "°" // , // degrees
39413 // "é" , // e ecute
39414 // "ú" , // u ecute?
39417 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39418 "input:submit", "input:button", "select", "textarea", "label" ],
39421 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39423 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39426 * @cfg {String} defaultFont default font to use.
39428 defaultFont: 'tahoma',
39430 fontSelect : false,
39433 formatCombo : false,
39435 init : function(editor)
39437 this.editor = editor;
39440 var fid = editor.frameId;
39442 function btn(id, toggle, handler){
39443 var xid = fid + '-'+ id ;
39447 cls : 'x-btn-icon x-edit-'+id,
39448 enableToggle:toggle !== false,
39449 scope: editor, // was editor...
39450 handler:handler||editor.relayBtnCmd,
39451 clickEvent:'mousedown',
39452 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39459 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39461 // stop form submits
39462 tb.el.on('click', function(e){
39463 e.preventDefault(); // what does this do?
39466 if(!this.disable.font && !Roo.isSafari){
39467 /* why no safari for fonts
39468 editor.fontSelect = tb.el.createChild({
39471 cls:'x-font-select',
39472 html: editor.createFontOptions()
39474 editor.fontSelect.on('change', function(){
39475 var font = editor.fontSelect.dom.value;
39476 editor.relayCmd('fontname', font);
39477 editor.deferFocus();
39480 editor.fontSelect.dom,
39485 if(!this.disable.formats){
39486 this.formatCombo = new Roo.form.ComboBox({
39487 store: new Roo.data.SimpleStore({
39490 data : this.formats // from states.js
39493 //autoCreate : {tag: "div", size: "20"},
39494 displayField:'tag',
39498 triggerAction: 'all',
39499 emptyText:'Add tag',
39500 selectOnFocus:true,
39503 'select': function(c, r, i) {
39504 editor.insertTag(r.get('tag'));
39510 tb.addField(this.formatCombo);
39514 if(!this.disable.format){
39521 if(!this.disable.fontSize){
39526 btn('increasefontsize', false, editor.adjustFont),
39527 btn('decreasefontsize', false, editor.adjustFont)
39532 if(this.disable.colors){
39535 id:editor.frameId +'-forecolor',
39536 cls:'x-btn-icon x-edit-forecolor',
39537 clickEvent:'mousedown',
39538 tooltip: this.buttonTips['forecolor'] || undefined,
39540 menu : new Roo.menu.ColorMenu({
39541 allowReselect: true,
39542 focus: Roo.emptyFn,
39545 selectHandler: function(cp, color){
39546 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39547 editor.deferFocus();
39550 clickEvent:'mousedown'
39553 id:editor.frameId +'backcolor',
39554 cls:'x-btn-icon x-edit-backcolor',
39555 clickEvent:'mousedown',
39556 tooltip: this.buttonTips['backcolor'] || undefined,
39558 menu : new Roo.menu.ColorMenu({
39559 focus: Roo.emptyFn,
39562 allowReselect: true,
39563 selectHandler: function(cp, color){
39565 editor.execCmd('useCSS', false);
39566 editor.execCmd('hilitecolor', color);
39567 editor.execCmd('useCSS', true);
39568 editor.deferFocus();
39570 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39571 Roo.isSafari || Roo.isIE ? '#'+color : color);
39572 editor.deferFocus();
39576 clickEvent:'mousedown'
39581 // now add all the items...
39584 if(!this.disable.alignments){
39587 btn('justifyleft'),
39588 btn('justifycenter'),
39589 btn('justifyright')
39593 //if(!Roo.isSafari){
39594 if(!this.disable.links){
39597 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39601 if(!this.disable.lists){
39604 btn('insertorderedlist'),
39605 btn('insertunorderedlist')
39608 if(!this.disable.sourceEdit){
39611 btn('sourceedit', true, function(btn){
39612 this.toggleSourceEdit(btn.pressed);
39619 // special menu.. - needs to be tidied up..
39620 if (!this.disable.special) {
39623 cls: 'x-edit-none',
39628 for (var i =0; i < this.specialChars.length; i++) {
39629 smenu.menu.items.push({
39631 html: this.specialChars[i],
39632 handler: function(a,b) {
39633 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39646 for(var i =0; i< this.btns.length;i++) {
39647 var b = this.btns[i];
39648 b.cls = 'x-edit-none';
39657 // disable everything...
39659 this.tb.items.each(function(item){
39660 if(item.id != editor.frameId+ '-sourceedit'){
39664 this.rendered = true;
39666 // the all the btns;
39667 editor.on('editorevent', this.updateToolbar, this);
39668 // other toolbars need to implement this..
39669 //editor.on('editmodechange', this.updateToolbar, this);
39675 * Protected method that will not generally be called directly. It triggers
39676 * a toolbar update by reading the markup state of the current selection in the editor.
39678 updateToolbar: function(){
39680 if(!this.editor.activated){
39681 this.editor.onFirstFocus();
39685 var btns = this.tb.items.map,
39686 doc = this.editor.doc,
39687 frameId = this.editor.frameId;
39689 if(!this.disable.font && !Roo.isSafari){
39691 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39692 if(name != this.fontSelect.dom.value){
39693 this.fontSelect.dom.value = name;
39697 if(!this.disable.format){
39698 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39699 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39700 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39702 if(!this.disable.alignments){
39703 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39704 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39705 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39707 if(!Roo.isSafari && !this.disable.lists){
39708 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39709 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39712 var ans = this.editor.getAllAncestors();
39713 if (this.formatCombo) {
39716 var store = this.formatCombo.store;
39717 this.formatCombo.setValue("");
39718 for (var i =0; i < ans.length;i++) {
39719 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39721 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39729 // hides menus... - so this cant be on a menu...
39730 Roo.menu.MenuMgr.hideAll();
39732 //this.editorsyncValue();
39736 createFontOptions : function(){
39737 var buf = [], fs = this.fontFamilies, ff, lc;
39738 for(var i = 0, len = fs.length; i< len; i++){
39740 lc = ff.toLowerCase();
39742 '<option value="',lc,'" style="font-family:',ff,';"',
39743 (this.defaultFont == lc ? ' selected="true">' : '>'),
39748 return buf.join('');
39751 toggleSourceEdit : function(sourceEditMode){
39752 if(sourceEditMode === undefined){
39753 sourceEditMode = !this.sourceEditMode;
39755 this.sourceEditMode = sourceEditMode === true;
39756 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39757 // just toggle the button?
39758 if(btn.pressed !== this.editor.sourceEditMode){
39759 btn.toggle(this.editor.sourceEditMode);
39763 if(this.sourceEditMode){
39764 this.tb.items.each(function(item){
39765 if(item.cmd != 'sourceedit'){
39771 if(this.initialized){
39772 this.tb.items.each(function(item){
39778 // tell the editor that it's been pressed..
39779 this.editor.toggleSourceEdit(sourceEditMode);
39783 * Object collection of toolbar tooltips for the buttons in the editor. The key
39784 * is the command id associated with that button and the value is a valid QuickTips object.
39789 title: 'Bold (Ctrl+B)',
39790 text: 'Make the selected text bold.',
39791 cls: 'x-html-editor-tip'
39794 title: 'Italic (Ctrl+I)',
39795 text: 'Make the selected text italic.',
39796 cls: 'x-html-editor-tip'
39804 title: 'Bold (Ctrl+B)',
39805 text: 'Make the selected text bold.',
39806 cls: 'x-html-editor-tip'
39809 title: 'Italic (Ctrl+I)',
39810 text: 'Make the selected text italic.',
39811 cls: 'x-html-editor-tip'
39814 title: 'Underline (Ctrl+U)',
39815 text: 'Underline the selected text.',
39816 cls: 'x-html-editor-tip'
39818 increasefontsize : {
39819 title: 'Grow Text',
39820 text: 'Increase the font size.',
39821 cls: 'x-html-editor-tip'
39823 decreasefontsize : {
39824 title: 'Shrink Text',
39825 text: 'Decrease the font size.',
39826 cls: 'x-html-editor-tip'
39829 title: 'Text Highlight Color',
39830 text: 'Change the background color of the selected text.',
39831 cls: 'x-html-editor-tip'
39834 title: 'Font Color',
39835 text: 'Change the color of the selected text.',
39836 cls: 'x-html-editor-tip'
39839 title: 'Align Text Left',
39840 text: 'Align text to the left.',
39841 cls: 'x-html-editor-tip'
39844 title: 'Center Text',
39845 text: 'Center text in the editor.',
39846 cls: 'x-html-editor-tip'
39849 title: 'Align Text Right',
39850 text: 'Align text to the right.',
39851 cls: 'x-html-editor-tip'
39853 insertunorderedlist : {
39854 title: 'Bullet List',
39855 text: 'Start a bulleted list.',
39856 cls: 'x-html-editor-tip'
39858 insertorderedlist : {
39859 title: 'Numbered List',
39860 text: 'Start a numbered list.',
39861 cls: 'x-html-editor-tip'
39864 title: 'Hyperlink',
39865 text: 'Make the selected text a hyperlink.',
39866 cls: 'x-html-editor-tip'
39869 title: 'Source Edit',
39870 text: 'Switch to source editing mode.',
39871 cls: 'x-html-editor-tip'
39875 onDestroy : function(){
39878 this.tb.items.each(function(item){
39880 item.menu.removeAll();
39882 item.menu.el.destroy();
39890 onFirstFocus: function() {
39891 this.tb.items.each(function(item){
39900 // <script type="text/javascript">
39903 * Ext JS Library 1.1.1
39904 * Copyright(c) 2006-2007, Ext JS, LLC.
39911 * @class Roo.form.HtmlEditor.ToolbarContext
39916 new Roo.form.HtmlEditor({
39919 new Roo.form.HtmlEditor.ToolbarStandard(),
39920 new Roo.form.HtmlEditor.ToolbarContext()
39925 * @config : {Object} disable List of elements to disable.. (not done yet.)
39930 Roo.form.HtmlEditor.ToolbarContext = function(config)
39933 Roo.apply(this, config);
39934 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39935 // dont call parent... till later.
39937 Roo.form.HtmlEditor.ToolbarContext.types = {
39949 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40011 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40016 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40080 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40088 * @cfg {Object} disable List of toolbar elements to disable
40097 init : function(editor)
40099 this.editor = editor;
40102 var fid = editor.frameId;
40104 function btn(id, toggle, handler){
40105 var xid = fid + '-'+ id ;
40109 cls : 'x-btn-icon x-edit-'+id,
40110 enableToggle:toggle !== false,
40111 scope: editor, // was editor...
40112 handler:handler||editor.relayBtnCmd,
40113 clickEvent:'mousedown',
40114 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40118 // create a new element.
40119 var wdiv = editor.wrap.createChild({
40121 }, editor.wrap.dom.firstChild.nextSibling, true);
40123 // can we do this more than once??
40125 // stop form submits
40128 // disable everything...
40129 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40130 this.toolbars = {};
40132 for (var i in ty) {
40134 this.toolbars[i] = this.buildToolbar(ty[i],i);
40136 this.tb = this.toolbars.BODY;
40140 this.rendered = true;
40142 // the all the btns;
40143 editor.on('editorevent', this.updateToolbar, this);
40144 // other toolbars need to implement this..
40145 //editor.on('editmodechange', this.updateToolbar, this);
40151 * Protected method that will not generally be called directly. It triggers
40152 * a toolbar update by reading the markup state of the current selection in the editor.
40154 updateToolbar: function(){
40156 if(!this.editor.activated){
40157 this.editor.onFirstFocus();
40162 var ans = this.editor.getAllAncestors();
40165 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40166 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40167 sel = sel ? sel : this.editor.doc.body;
40168 sel = sel.tagName.length ? sel : this.editor.doc.body;
40169 var tn = sel.tagName.toUpperCase();
40170 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40171 tn = sel.tagName.toUpperCase();
40172 if (this.tb.name == tn) {
40173 return; // no change
40176 ///console.log("show: " + tn);
40177 this.tb = this.toolbars[tn];
40179 this.tb.fields.each(function(e) {
40180 e.setValue(sel.getAttribute(e.name));
40182 this.tb.selectedNode = sel;
40185 Roo.menu.MenuMgr.hideAll();
40187 //this.editorsyncValue();
40192 onDestroy : function(){
40195 this.tb.items.each(function(item){
40197 item.menu.removeAll();
40199 item.menu.el.destroy();
40207 onFirstFocus: function() {
40208 // need to do this for all the toolbars..
40209 this.tb.items.each(function(item){
40213 buildToolbar: function(tlist, nm)
40215 var editor = this.editor;
40216 // create a new element.
40217 var wdiv = editor.wrap.createChild({
40219 }, editor.wrap.dom.firstChild.nextSibling, true);
40222 var tb = new Roo.Toolbar(wdiv);
40223 tb.add(nm+ ": ");
40224 for (var i in tlist) {
40225 var item = tlist[i];
40226 tb.add(item.title + ": ");
40231 tb.addField( new Roo.form.ComboBox({
40232 store: new Roo.data.SimpleStore({
40235 data : item.opts // from states.js
40238 displayField:'val',
40242 triggerAction: 'all',
40243 emptyText:'Select',
40244 selectOnFocus:true,
40245 width: item.width ? item.width : 130,
40247 'select': function(c, r, i) {
40248 tb.selectedNode.setAttribute(c.name, r.get('val'));
40259 tb.addField( new Roo.form.TextField({
40262 //allowBlank:false,
40267 tb.addField( new Roo.form.TextField({
40273 'change' : function(f, nv, ov) {
40274 tb.selectedNode.setAttribute(f.name, nv);
40280 tb.el.on('click', function(e){
40281 e.preventDefault(); // what does this do?
40283 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40286 // dont need to disable them... as they will get hidden
40303 * Ext JS Library 1.1.1
40304 * Copyright(c) 2006-2007, Ext JS, LLC.
40306 * Originally Released Under LGPL - original licence link has changed is not relivant.
40309 * <script type="text/javascript">
40313 * @class Roo.form.BasicForm
40314 * @extends Roo.util.Observable
40315 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40317 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40318 * @param {Object} config Configuration options
40320 Roo.form.BasicForm = function(el, config){
40321 this.allItems = [];
40322 this.childForms = [];
40323 Roo.apply(this, config);
40325 * The Roo.form.Field items in this form.
40326 * @type MixedCollection
40330 this.items = new Roo.util.MixedCollection(false, function(o){
40331 return o.id || (o.id = Roo.id());
40335 * @event beforeaction
40336 * Fires before any action is performed. Return false to cancel the action.
40337 * @param {Form} this
40338 * @param {Action} action The action to be performed
40340 beforeaction: true,
40342 * @event actionfailed
40343 * Fires when an action fails.
40344 * @param {Form} this
40345 * @param {Action} action The action that failed
40347 actionfailed : true,
40349 * @event actioncomplete
40350 * Fires when an action is completed.
40351 * @param {Form} this
40352 * @param {Action} action The action that completed
40354 actioncomplete : true
40359 Roo.form.BasicForm.superclass.constructor.call(this);
40362 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40364 * @cfg {String} method
40365 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40368 * @cfg {DataReader} reader
40369 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40370 * This is optional as there is built-in support for processing JSON.
40373 * @cfg {DataReader} errorReader
40374 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40375 * This is completely optional as there is built-in support for processing JSON.
40378 * @cfg {String} url
40379 * The URL to use for form actions if one isn't supplied in the action options.
40382 * @cfg {Boolean} fileUpload
40383 * Set to true if this form is a file upload.
40387 * @cfg {Object} baseParams
40388 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40393 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40398 activeAction : null,
40401 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40402 * or setValues() data instead of when the form was first created.
40404 trackResetOnLoad : false,
40408 * childForms - used for multi-tab forms
40411 childForms : false,
40414 * allItems - full list of fields.
40420 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40421 * element by passing it or its id or mask the form itself by passing in true.
40424 waitMsgTarget : false,
40427 initEl : function(el){
40428 this.el = Roo.get(el);
40429 this.id = this.el.id || Roo.id();
40430 this.el.on('submit', this.onSubmit, this);
40431 this.el.addClass('x-form');
40435 onSubmit : function(e){
40440 * Returns true if client-side validation on the form is successful.
40443 isValid : function(){
40445 this.items.each(function(f){
40454 * Returns true if any fields in this form have changed since their original load.
40457 isDirty : function(){
40459 this.items.each(function(f){
40469 * Performs a predefined action (submit or load) or custom actions you define on this form.
40470 * @param {String} actionName The name of the action type
40471 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40472 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40473 * accept other config options):
40475 Property Type Description
40476 ---------------- --------------- ----------------------------------------------------------------------------------
40477 url String The url for the action (defaults to the form's url)
40478 method String The form method to use (defaults to the form's method, or POST if not defined)
40479 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40480 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40481 validate the form on the client (defaults to false)
40483 * @return {BasicForm} this
40485 doAction : function(action, options){
40486 if(typeof action == 'string'){
40487 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40489 if(this.fireEvent('beforeaction', this, action) !== false){
40490 this.beforeAction(action);
40491 action.run.defer(100, action);
40497 * Shortcut to do a submit action.
40498 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40499 * @return {BasicForm} this
40501 submit : function(options){
40502 this.doAction('submit', options);
40507 * Shortcut to do a load action.
40508 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40509 * @return {BasicForm} this
40511 load : function(options){
40512 this.doAction('load', options);
40517 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40518 * @param {Record} record The record to edit
40519 * @return {BasicForm} this
40521 updateRecord : function(record){
40522 record.beginEdit();
40523 var fs = record.fields;
40524 fs.each(function(f){
40525 var field = this.findField(f.name);
40527 record.set(f.name, field.getValue());
40535 * Loads an Roo.data.Record into this form.
40536 * @param {Record} record The record to load
40537 * @return {BasicForm} this
40539 loadRecord : function(record){
40540 this.setValues(record.data);
40545 beforeAction : function(action){
40546 var o = action.options;
40549 if(this.waitMsgTarget === true){
40550 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
40551 }else if(this.waitMsgTarget){
40552 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40553 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
40555 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
40561 afterAction : function(action, success){
40562 this.activeAction = null;
40563 var o = action.options;
40565 if(this.waitMsgTarget === true){
40567 }else if(this.waitMsgTarget){
40568 this.waitMsgTarget.unmask();
40570 Roo.MessageBox.updateProgress(1);
40571 Roo.MessageBox.hide();
40578 Roo.callback(o.success, o.scope, [this, action]);
40579 this.fireEvent('actioncomplete', this, action);
40582 Roo.callback(o.failure, o.scope, [this, action]);
40583 // show an error message if no failed handler is set..
40584 if (!this.hasListener('actionfailed')) {
40585 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
40588 this.fireEvent('actionfailed', this, action);
40594 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40595 * @param {String} id The value to search for
40598 findField : function(id){
40599 var field = this.items.get(id);
40601 this.items.each(function(f){
40602 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40608 return field || null;
40612 * Add a secondary form to this one,
40613 * Used to provide tabbed forms. One form is primary, with hidden values
40614 * which mirror the elements from the other forms.
40616 * @param {Roo.form.Form} form to add.
40619 addForm : function(form)
40622 if (this.childForms.indexOf(form) > -1) {
40626 this.childForms.push(form);
40628 Roo.each(form.allItems, function (fe) {
40630 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40631 if (this.findField(n)) { // already added..
40634 var add = new Roo.form.Hidden({
40637 add.render(this.el);
40644 * Mark fields in this form invalid in bulk.
40645 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40646 * @return {BasicForm} this
40648 markInvalid : function(errors){
40649 if(errors instanceof Array){
40650 for(var i = 0, len = errors.length; i < len; i++){
40651 var fieldError = errors[i];
40652 var f = this.findField(fieldError.id);
40654 f.markInvalid(fieldError.msg);
40660 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40661 field.markInvalid(errors[id]);
40665 Roo.each(this.childForms || [], function (f) {
40666 f.markInvalid(errors);
40673 * Set values for fields in this form in bulk.
40674 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40675 * @return {BasicForm} this
40677 setValues : function(values){
40678 if(values instanceof Array){ // array of objects
40679 for(var i = 0, len = values.length; i < len; i++){
40681 var f = this.findField(v.id);
40683 f.setValue(v.value);
40684 if(this.trackResetOnLoad){
40685 f.originalValue = f.getValue();
40689 }else{ // object hash
40692 if(typeof values[id] != 'function' && (field = this.findField(id))){
40694 if (field.setFromData &&
40695 field.valueField &&
40696 field.displayField &&
40697 // combos' with local stores can
40698 // be queried via setValue()
40699 // to set their value..
40700 (field.store && !field.store.isLocal)
40704 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40705 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40706 field.setFromData(sd);
40709 field.setValue(values[id]);
40713 if(this.trackResetOnLoad){
40714 field.originalValue = field.getValue();
40720 Roo.each(this.childForms || [], function (f) {
40721 f.setValues(values);
40728 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40729 * they are returned as an array.
40730 * @param {Boolean} asString
40733 getValues : function(asString){
40734 if (this.childForms) {
40735 // copy values from the child forms
40736 Roo.each(this.childForms, function (f) {
40737 this.setValues(f.getValues());
40743 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40744 if(asString === true){
40747 return Roo.urlDecode(fs);
40751 * Returns the fields in this form as an object with key/value pairs.
40752 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40755 getFieldValues : function()
40757 if (this.childForms) {
40758 // copy values from the child forms
40759 Roo.each(this.childForms, function (f) {
40760 this.setValues(f.getValues());
40765 this.items.each(function(f){
40766 if (!f.getName()) {
40769 var v = f.getValue();
40770 if ((typeof(v) == 'object') && f.getRawValue) {
40771 v = f.getRawValue() ; // dates..
40773 ret[f.getName()] = v;
40780 * Clears all invalid messages in this form.
40781 * @return {BasicForm} this
40783 clearInvalid : function(){
40784 this.items.each(function(f){
40788 Roo.each(this.childForms || [], function (f) {
40797 * Resets this form.
40798 * @return {BasicForm} this
40800 reset : function(){
40801 this.items.each(function(f){
40805 Roo.each(this.childForms || [], function (f) {
40814 * Add Roo.form components to this form.
40815 * @param {Field} field1
40816 * @param {Field} field2 (optional)
40817 * @param {Field} etc (optional)
40818 * @return {BasicForm} this
40821 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40827 * Removes a field from the items collection (does NOT remove its markup).
40828 * @param {Field} field
40829 * @return {BasicForm} this
40831 remove : function(field){
40832 this.items.remove(field);
40837 * Looks at the fields in this form, checks them for an id attribute,
40838 * and calls applyTo on the existing dom element with that id.
40839 * @return {BasicForm} this
40841 render : function(){
40842 this.items.each(function(f){
40843 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40851 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40852 * @param {Object} values
40853 * @return {BasicForm} this
40855 applyToFields : function(o){
40856 this.items.each(function(f){
40863 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40864 * @param {Object} values
40865 * @return {BasicForm} this
40867 applyIfToFields : function(o){
40868 this.items.each(function(f){
40876 Roo.BasicForm = Roo.form.BasicForm;/*
40878 * Ext JS Library 1.1.1
40879 * Copyright(c) 2006-2007, Ext JS, LLC.
40881 * Originally Released Under LGPL - original licence link has changed is not relivant.
40884 * <script type="text/javascript">
40888 * @class Roo.form.Form
40889 * @extends Roo.form.BasicForm
40890 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40892 * @param {Object} config Configuration options
40894 Roo.form.Form = function(config){
40896 if (config.items) {
40897 xitems = config.items;
40898 delete config.items;
40902 Roo.form.Form.superclass.constructor.call(this, null, config);
40903 this.url = this.url || this.action;
40905 this.root = new Roo.form.Layout(Roo.applyIf({
40909 this.active = this.root;
40911 * Array of all the buttons that have been added to this form via {@link addButton}
40915 this.allItems = [];
40918 * @event clientvalidation
40919 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40920 * @param {Form} this
40921 * @param {Boolean} valid true if the form has passed client-side validation
40923 clientvalidation: true,
40926 * Fires when the form is rendered
40927 * @param {Roo.form.Form} form
40932 if (this.progressUrl) {
40933 // push a hidden field onto the list of fields..
40937 name : 'UPLOAD_IDENTIFIER'
40942 Roo.each(xitems, this.addxtype, this);
40948 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40950 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40953 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40956 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40958 buttonAlign:'center',
40961 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40966 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40967 * This property cascades to child containers if not set.
40972 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40973 * fires a looping event with that state. This is required to bind buttons to the valid
40974 * state using the config value formBind:true on the button.
40976 monitorValid : false,
40979 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40984 * @cfg {String} progressUrl - Url to return progress data
40987 progressUrl : false,
40990 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40991 * fields are added and the column is closed. If no fields are passed the column remains open
40992 * until end() is called.
40993 * @param {Object} config The config to pass to the column
40994 * @param {Field} field1 (optional)
40995 * @param {Field} field2 (optional)
40996 * @param {Field} etc (optional)
40997 * @return Column The column container object
40999 column : function(c){
41000 var col = new Roo.form.Column(c);
41002 if(arguments.length > 1){ // duplicate code required because of Opera
41003 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41010 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41011 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41012 * until end() is called.
41013 * @param {Object} config The config to pass to the fieldset
41014 * @param {Field} field1 (optional)
41015 * @param {Field} field2 (optional)
41016 * @param {Field} etc (optional)
41017 * @return FieldSet The fieldset container object
41019 fieldset : function(c){
41020 var fs = new Roo.form.FieldSet(c);
41022 if(arguments.length > 1){ // duplicate code required because of Opera
41023 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41030 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41031 * fields are added and the container is closed. If no fields are passed the container remains open
41032 * until end() is called.
41033 * @param {Object} config The config to pass to the Layout
41034 * @param {Field} field1 (optional)
41035 * @param {Field} field2 (optional)
41036 * @param {Field} etc (optional)
41037 * @return Layout The container object
41039 container : function(c){
41040 var l = new Roo.form.Layout(c);
41042 if(arguments.length > 1){ // duplicate code required because of Opera
41043 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41050 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41051 * @param {Object} container A Roo.form.Layout or subclass of Layout
41052 * @return {Form} this
41054 start : function(c){
41055 // cascade label info
41056 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41057 this.active.stack.push(c);
41058 c.ownerCt = this.active;
41064 * Closes the current open container
41065 * @return {Form} this
41068 if(this.active == this.root){
41071 this.active = this.active.ownerCt;
41076 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41077 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41078 * as the label of the field.
41079 * @param {Field} field1
41080 * @param {Field} field2 (optional)
41081 * @param {Field} etc. (optional)
41082 * @return {Form} this
41085 this.active.stack.push.apply(this.active.stack, arguments);
41086 this.allItems.push.apply(this.allItems,arguments);
41088 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41089 if(a[i].isFormField){
41094 Roo.form.Form.superclass.add.apply(this, r);
41104 * Find any element that has been added to a form, using it's ID or name
41105 * This can include framesets, columns etc. along with regular fields..
41106 * @param {String} id - id or name to find.
41108 * @return {Element} e - or false if nothing found.
41110 findbyId : function(id)
41116 Ext.each(this.allItems, function(f){
41117 if (f.id == id || f.name == id ){
41128 * Render this form into the passed container. This should only be called once!
41129 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41130 * @return {Form} this
41132 render : function(ct)
41138 var o = this.autoCreate || {
41140 method : this.method || 'POST',
41141 id : this.id || Roo.id()
41143 this.initEl(ct.createChild(o));
41145 this.root.render(this.el);
41149 this.items.each(function(f){
41150 f.render('x-form-el-'+f.id);
41153 if(this.buttons.length > 0){
41154 // tables are required to maintain order and for correct IE layout
41155 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41156 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41157 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41159 var tr = tb.getElementsByTagName('tr')[0];
41160 for(var i = 0, len = this.buttons.length; i < len; i++) {
41161 var b = this.buttons[i];
41162 var td = document.createElement('td');
41163 td.className = 'x-form-btn-td';
41164 b.render(tr.appendChild(td));
41167 if(this.monitorValid){ // initialize after render
41168 this.startMonitoring();
41170 this.fireEvent('rendered', this);
41175 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41176 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41177 * object or a valid Roo.DomHelper element config
41178 * @param {Function} handler The function called when the button is clicked
41179 * @param {Object} scope (optional) The scope of the handler function
41180 * @return {Roo.Button}
41182 addButton : function(config, handler, scope){
41186 minWidth: this.minButtonWidth,
41189 if(typeof config == "string"){
41192 Roo.apply(bc, config);
41194 var btn = new Roo.Button(null, bc);
41195 this.buttons.push(btn);
41200 * Adds a series of form elements (using the xtype property as the factory method.
41201 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41202 * @param {Object} config
41205 addxtype : function()
41207 var ar = Array.prototype.slice.call(arguments, 0);
41209 for(var i = 0; i < ar.length; i++) {
41211 continue; // skip -- if this happends something invalid got sent, we
41212 // should ignore it, as basically that interface element will not show up
41213 // and that should be pretty obvious!!
41216 if (Roo.form[ar[i].xtype]) {
41218 var fe = Roo.factory(ar[i], Roo.form);
41224 fe.store.form = this;
41229 this.allItems.push(fe);
41230 if (fe.items && fe.addxtype) {
41231 fe.addxtype.apply(fe, fe.items);
41241 // console.log('adding ' + ar[i].xtype);
41243 if (ar[i].xtype == 'Button') {
41244 //console.log('adding button');
41245 //console.log(ar[i]);
41246 this.addButton(ar[i]);
41247 this.allItems.push(fe);
41251 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41252 alert('end is not supported on xtype any more, use items');
41254 // //console.log('adding end');
41262 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41263 * option "monitorValid"
41265 startMonitoring : function(){
41268 Roo.TaskMgr.start({
41269 run : this.bindHandler,
41270 interval : this.monitorPoll || 200,
41277 * Stops monitoring of the valid state of this form
41279 stopMonitoring : function(){
41280 this.bound = false;
41284 bindHandler : function(){
41286 return false; // stops binding
41289 this.items.each(function(f){
41290 if(!f.isValid(true)){
41295 for(var i = 0, len = this.buttons.length; i < len; i++){
41296 var btn = this.buttons[i];
41297 if(btn.formBind === true && btn.disabled === valid){
41298 btn.setDisabled(!valid);
41301 this.fireEvent('clientvalidation', this, valid);
41315 Roo.Form = Roo.form.Form;
41318 * Ext JS Library 1.1.1
41319 * Copyright(c) 2006-2007, Ext JS, LLC.
41321 * Originally Released Under LGPL - original licence link has changed is not relivant.
41324 * <script type="text/javascript">
41328 * @class Roo.form.Action
41329 * Internal Class used to handle form actions
41331 * @param {Roo.form.BasicForm} el The form element or its id
41332 * @param {Object} config Configuration options
41336 // define the action interface
41337 Roo.form.Action = function(form, options){
41339 this.options = options || {};
41342 * Client Validation Failed
41345 Roo.form.Action.CLIENT_INVALID = 'client';
41347 * Server Validation Failed
41350 Roo.form.Action.SERVER_INVALID = 'server';
41352 * Connect to Server Failed
41355 Roo.form.Action.CONNECT_FAILURE = 'connect';
41357 * Reading Data from Server Failed
41360 Roo.form.Action.LOAD_FAILURE = 'load';
41362 Roo.form.Action.prototype = {
41364 failureType : undefined,
41365 response : undefined,
41366 result : undefined,
41368 // interface method
41369 run : function(options){
41373 // interface method
41374 success : function(response){
41378 // interface method
41379 handleResponse : function(response){
41383 // default connection failure
41384 failure : function(response){
41386 this.response = response;
41387 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41388 this.form.afterAction(this, false);
41391 processResponse : function(response){
41392 this.response = response;
41393 if(!response.responseText){
41396 this.result = this.handleResponse(response);
41397 return this.result;
41400 // utility functions used internally
41401 getUrl : function(appendParams){
41402 var url = this.options.url || this.form.url || this.form.el.dom.action;
41404 var p = this.getParams();
41406 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41412 getMethod : function(){
41413 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41416 getParams : function(){
41417 var bp = this.form.baseParams;
41418 var p = this.options.params;
41420 if(typeof p == "object"){
41421 p = Roo.urlEncode(Roo.applyIf(p, bp));
41422 }else if(typeof p == 'string' && bp){
41423 p += '&' + Roo.urlEncode(bp);
41426 p = Roo.urlEncode(bp);
41431 createCallback : function(){
41433 success: this.success,
41434 failure: this.failure,
41436 timeout: (this.form.timeout*1000),
41437 upload: this.form.fileUpload ? this.success : undefined
41442 Roo.form.Action.Submit = function(form, options){
41443 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41446 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41449 haveProgress : false,
41450 uploadComplete : false,
41452 // uploadProgress indicator.
41453 uploadProgress : function()
41455 if (!this.form.progressUrl) {
41459 if (!this.haveProgress) {
41460 Roo.MessageBox.progress("Uploading", "Uploading");
41462 if (this.uploadComplete) {
41463 Roo.MessageBox.hide();
41467 this.haveProgress = true;
41469 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41471 var c = new Roo.data.Connection();
41473 url : this.form.progressUrl,
41478 success : function(req){
41479 //console.log(data);
41483 rdata = Roo.decode(req.responseText)
41485 Roo.log("Invalid data from server..");
41489 if (!rdata || !rdata.success) {
41493 var data = rdata.data;
41495 if (this.uploadComplete) {
41496 Roo.MessageBox.hide();
41501 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41502 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41505 this.uploadProgress.defer(2000,this);
41508 failure: function(data) {
41509 Roo.log('progress url failed ');
41520 // run get Values on the form, so it syncs any secondary forms.
41521 this.form.getValues();
41523 var o = this.options;
41524 var method = this.getMethod();
41525 var isPost = method == 'POST';
41526 if(o.clientValidation === false || this.form.isValid()){
41528 if (this.form.progressUrl) {
41529 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41530 (new Date() * 1) + '' + Math.random());
41535 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41536 form:this.form.el.dom,
41537 url:this.getUrl(!isPost),
41539 params:isPost ? this.getParams() : null,
41540 isUpload: this.form.fileUpload
41543 this.uploadProgress();
41545 }else if (o.clientValidation !== false){ // client validation failed
41546 this.failureType = Roo.form.Action.CLIENT_INVALID;
41547 this.form.afterAction(this, false);
41551 success : function(response)
41553 this.uploadComplete= true;
41554 if (this.haveProgress) {
41555 Roo.MessageBox.hide();
41559 var result = this.processResponse(response);
41560 if(result === true || result.success){
41561 this.form.afterAction(this, true);
41565 this.form.markInvalid(result.errors);
41566 this.failureType = Roo.form.Action.SERVER_INVALID;
41568 this.form.afterAction(this, false);
41570 failure : function(response)
41572 this.uploadComplete= true;
41573 if (this.haveProgress) {
41574 Roo.MessageBox.hide();
41578 this.response = response;
41579 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41580 this.form.afterAction(this, false);
41583 handleResponse : function(response){
41584 if(this.form.errorReader){
41585 var rs = this.form.errorReader.read(response);
41588 for(var i = 0, len = rs.records.length; i < len; i++) {
41589 var r = rs.records[i];
41590 errors[i] = r.data;
41593 if(errors.length < 1){
41597 success : rs.success,
41603 ret = Roo.decode(response.responseText);
41607 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41617 Roo.form.Action.Load = function(form, options){
41618 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41619 this.reader = this.form.reader;
41622 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41627 Roo.Ajax.request(Roo.apply(
41628 this.createCallback(), {
41629 method:this.getMethod(),
41630 url:this.getUrl(false),
41631 params:this.getParams()
41635 success : function(response){
41637 var result = this.processResponse(response);
41638 if(result === true || !result.success || !result.data){
41639 this.failureType = Roo.form.Action.LOAD_FAILURE;
41640 this.form.afterAction(this, false);
41643 this.form.clearInvalid();
41644 this.form.setValues(result.data);
41645 this.form.afterAction(this, true);
41648 handleResponse : function(response){
41649 if(this.form.reader){
41650 var rs = this.form.reader.read(response);
41651 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41653 success : rs.success,
41657 return Roo.decode(response.responseText);
41661 Roo.form.Action.ACTION_TYPES = {
41662 'load' : Roo.form.Action.Load,
41663 'submit' : Roo.form.Action.Submit
41666 * Ext JS Library 1.1.1
41667 * Copyright(c) 2006-2007, Ext JS, LLC.
41669 * Originally Released Under LGPL - original licence link has changed is not relivant.
41672 * <script type="text/javascript">
41676 * @class Roo.form.Layout
41677 * @extends Roo.Component
41678 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41680 * @param {Object} config Configuration options
41682 Roo.form.Layout = function(config){
41684 if (config.items) {
41685 xitems = config.items;
41686 delete config.items;
41688 Roo.form.Layout.superclass.constructor.call(this, config);
41690 Roo.each(xitems, this.addxtype, this);
41694 Roo.extend(Roo.form.Layout, Roo.Component, {
41696 * @cfg {String/Object} autoCreate
41697 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41700 * @cfg {String/Object/Function} style
41701 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41702 * a function which returns such a specification.
41705 * @cfg {String} labelAlign
41706 * Valid values are "left," "top" and "right" (defaults to "left")
41709 * @cfg {Number} labelWidth
41710 * Fixed width in pixels of all field labels (defaults to undefined)
41713 * @cfg {Boolean} clear
41714 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41718 * @cfg {String} labelSeparator
41719 * The separator to use after field labels (defaults to ':')
41721 labelSeparator : ':',
41723 * @cfg {Boolean} hideLabels
41724 * True to suppress the display of field labels in this layout (defaults to false)
41726 hideLabels : false,
41729 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41734 onRender : function(ct, position){
41735 if(this.el){ // from markup
41736 this.el = Roo.get(this.el);
41737 }else { // generate
41738 var cfg = this.getAutoCreate();
41739 this.el = ct.createChild(cfg, position);
41742 this.el.applyStyles(this.style);
41744 if(this.labelAlign){
41745 this.el.addClass('x-form-label-'+this.labelAlign);
41747 if(this.hideLabels){
41748 this.labelStyle = "display:none";
41749 this.elementStyle = "padding-left:0;";
41751 if(typeof this.labelWidth == 'number'){
41752 this.labelStyle = "width:"+this.labelWidth+"px;";
41753 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41755 if(this.labelAlign == 'top'){
41756 this.labelStyle = "width:auto;";
41757 this.elementStyle = "padding-left:0;";
41760 var stack = this.stack;
41761 var slen = stack.length;
41763 if(!this.fieldTpl){
41764 var t = new Roo.Template(
41765 '<div class="x-form-item {5}">',
41766 '<label for="{0}" style="{2}">{1}{4}</label>',
41767 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41769 '</div><div class="x-form-clear-left"></div>'
41771 t.disableFormats = true;
41773 Roo.form.Layout.prototype.fieldTpl = t;
41775 for(var i = 0; i < slen; i++) {
41776 if(stack[i].isFormField){
41777 this.renderField(stack[i]);
41779 this.renderComponent(stack[i]);
41784 this.el.createChild({cls:'x-form-clear'});
41789 renderField : function(f){
41790 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41793 f.labelStyle||this.labelStyle||'', //2
41794 this.elementStyle||'', //3
41795 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41796 f.itemCls||this.itemCls||'' //5
41797 ], true).getPrevSibling());
41801 renderComponent : function(c){
41802 c.render(c.isLayout ? this.el : this.el.createChild());
41805 * Adds a object form elements (using the xtype property as the factory method.)
41806 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41807 * @param {Object} config
41809 addxtype : function(o)
41811 // create the lement.
41812 o.form = this.form;
41813 var fe = Roo.factory(o, Roo.form);
41814 this.form.allItems.push(fe);
41815 this.stack.push(fe);
41817 if (fe.isFormField) {
41818 this.form.items.add(fe);
41826 * @class Roo.form.Column
41827 * @extends Roo.form.Layout
41828 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41830 * @param {Object} config Configuration options
41832 Roo.form.Column = function(config){
41833 Roo.form.Column.superclass.constructor.call(this, config);
41836 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41838 * @cfg {Number/String} width
41839 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41842 * @cfg {String/Object} autoCreate
41843 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41847 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41850 onRender : function(ct, position){
41851 Roo.form.Column.superclass.onRender.call(this, ct, position);
41853 this.el.setWidth(this.width);
41860 * @class Roo.form.Row
41861 * @extends Roo.form.Layout
41862 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41864 * @param {Object} config Configuration options
41868 Roo.form.Row = function(config){
41869 Roo.form.Row.superclass.constructor.call(this, config);
41872 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41874 * @cfg {Number/String} width
41875 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41878 * @cfg {Number/String} height
41879 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41881 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41885 onRender : function(ct, position){
41886 //console.log('row render');
41888 var t = new Roo.Template(
41889 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41890 '<label for="{0}" style="{2}">{1}{4}</label>',
41891 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41895 t.disableFormats = true;
41897 Roo.form.Layout.prototype.rowTpl = t;
41899 this.fieldTpl = this.rowTpl;
41901 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41902 var labelWidth = 100;
41904 if ((this.labelAlign != 'top')) {
41905 if (typeof this.labelWidth == 'number') {
41906 labelWidth = this.labelWidth
41908 this.padWidth = 20 + labelWidth;
41912 Roo.form.Column.superclass.onRender.call(this, ct, position);
41914 this.el.setWidth(this.width);
41917 this.el.setHeight(this.height);
41922 renderField : function(f){
41923 f.fieldEl = this.fieldTpl.append(this.el, [
41924 f.id, f.fieldLabel,
41925 f.labelStyle||this.labelStyle||'',
41926 this.elementStyle||'',
41927 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41928 f.itemCls||this.itemCls||'',
41929 f.width ? f.width + this.padWidth : 160 + this.padWidth
41936 * @class Roo.form.FieldSet
41937 * @extends Roo.form.Layout
41938 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41940 * @param {Object} config Configuration options
41942 Roo.form.FieldSet = function(config){
41943 Roo.form.FieldSet.superclass.constructor.call(this, config);
41946 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41948 * @cfg {String} legend
41949 * The text to display as the legend for the FieldSet (defaults to '')
41952 * @cfg {String/Object} autoCreate
41953 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41957 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41960 onRender : function(ct, position){
41961 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
41963 this.setLegend(this.legend);
41968 setLegend : function(text){
41970 this.el.child('legend').update(text);
41975 * Ext JS Library 1.1.1
41976 * Copyright(c) 2006-2007, Ext JS, LLC.
41978 * Originally Released Under LGPL - original licence link has changed is not relivant.
41981 * <script type="text/javascript">
41984 * @class Roo.form.VTypes
41985 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41988 Roo.form.VTypes = function(){
41989 // closure these in so they are only created once.
41990 var alpha = /^[a-zA-Z_]+$/;
41991 var alphanum = /^[a-zA-Z0-9_]+$/;
41992 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41993 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41995 // All these messages and functions are configurable
41998 * The function used to validate email addresses
41999 * @param {String} value The email address
42001 'email' : function(v){
42002 return email.test(v);
42005 * The error text to display when the email validation function returns false
42008 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42010 * The keystroke filter mask to be applied on email input
42013 'emailMask' : /[a-z0-9_\.\-@]/i,
42016 * The function used to validate URLs
42017 * @param {String} value The URL
42019 'url' : function(v){
42020 return url.test(v);
42023 * The error text to display when the url validation function returns false
42026 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42029 * The function used to validate alpha values
42030 * @param {String} value The value
42032 'alpha' : function(v){
42033 return alpha.test(v);
42036 * The error text to display when the alpha validation function returns false
42039 'alphaText' : 'This field should only contain letters and _',
42041 * The keystroke filter mask to be applied on alpha input
42044 'alphaMask' : /[a-z_]/i,
42047 * The function used to validate alphanumeric values
42048 * @param {String} value The value
42050 'alphanum' : function(v){
42051 return alphanum.test(v);
42054 * The error text to display when the alphanumeric validation function returns false
42057 'alphanumText' : 'This field should only contain letters, numbers and _',
42059 * The keystroke filter mask to be applied on alphanumeric input
42062 'alphanumMask' : /[a-z0-9_]/i
42064 }();//<script type="text/javascript">
42067 * @class Roo.form.FCKeditor
42068 * @extends Roo.form.TextArea
42069 * Wrapper around the FCKEditor http://www.fckeditor.net
42071 * Creates a new FCKeditor
42072 * @param {Object} config Configuration options
42074 Roo.form.FCKeditor = function(config){
42075 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42078 * @event editorinit
42079 * Fired when the editor is initialized - you can add extra handlers here..
42080 * @param {FCKeditor} this
42081 * @param {Object} the FCK object.
42088 Roo.form.FCKeditor.editors = { };
42089 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42091 //defaultAutoCreate : {
42092 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42096 * @cfg {Object} fck options - see fck manual for details.
42101 * @cfg {Object} fck toolbar set (Basic or Default)
42103 toolbarSet : 'Basic',
42105 * @cfg {Object} fck BasePath
42107 basePath : '/fckeditor/',
42115 onRender : function(ct, position)
42118 this.defaultAutoCreate = {
42120 style:"width:300px;height:60px;",
42121 autocomplete: "off"
42124 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42127 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42128 if(this.preventScrollbars){
42129 this.el.setStyle("overflow", "hidden");
42131 this.el.setHeight(this.growMin);
42134 //console.log('onrender' + this.getId() );
42135 Roo.form.FCKeditor.editors[this.getId()] = this;
42138 this.replaceTextarea() ;
42142 getEditor : function() {
42143 return this.fckEditor;
42146 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42147 * @param {Mixed} value The value to set
42151 setValue : function(value)
42153 //console.log('setValue: ' + value);
42155 if(typeof(value) == 'undefined') { // not sure why this is happending...
42158 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42160 //if(!this.el || !this.getEditor()) {
42161 // this.value = value;
42162 //this.setValue.defer(100,this,[value]);
42166 if(!this.getEditor()) {
42170 this.getEditor().SetData(value);
42177 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42178 * @return {Mixed} value The field value
42180 getValue : function()
42183 if (this.frame && this.frame.dom.style.display == 'none') {
42184 return Roo.form.FCKeditor.superclass.getValue.call(this);
42187 if(!this.el || !this.getEditor()) {
42189 // this.getValue.defer(100,this);
42194 var value=this.getEditor().GetData();
42195 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42196 return Roo.form.FCKeditor.superclass.getValue.call(this);
42202 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42203 * @return {Mixed} value The field value
42205 getRawValue : function()
42207 if (this.frame && this.frame.dom.style.display == 'none') {
42208 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42211 if(!this.el || !this.getEditor()) {
42212 //this.getRawValue.defer(100,this);
42219 var value=this.getEditor().GetData();
42220 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42221 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42225 setSize : function(w,h) {
42229 //if (this.frame && this.frame.dom.style.display == 'none') {
42230 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42233 //if(!this.el || !this.getEditor()) {
42234 // this.setSize.defer(100,this, [w,h]);
42240 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42242 this.frame.dom.setAttribute('width', w);
42243 this.frame.dom.setAttribute('height', h);
42244 this.frame.setSize(w,h);
42248 toggleSourceEdit : function(value) {
42252 this.el.dom.style.display = value ? '' : 'none';
42253 this.frame.dom.style.display = value ? 'none' : '';
42258 focus: function(tag)
42260 if (this.frame.dom.style.display == 'none') {
42261 return Roo.form.FCKeditor.superclass.focus.call(this);
42263 if(!this.el || !this.getEditor()) {
42264 this.focus.defer(100,this, [tag]);
42271 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42272 this.getEditor().Focus();
42274 if (!this.getEditor().Selection.GetSelection()) {
42275 this.focus.defer(100,this, [tag]);
42280 var r = this.getEditor().EditorDocument.createRange();
42281 r.setStart(tgs[0],0);
42282 r.setEnd(tgs[0],0);
42283 this.getEditor().Selection.GetSelection().removeAllRanges();
42284 this.getEditor().Selection.GetSelection().addRange(r);
42285 this.getEditor().Focus();
42292 replaceTextarea : function()
42294 if ( document.getElementById( this.getId() + '___Frame' ) )
42296 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42298 // We must check the elements firstly using the Id and then the name.
42299 var oTextarea = document.getElementById( this.getId() );
42301 var colElementsByName = document.getElementsByName( this.getId() ) ;
42303 oTextarea.style.display = 'none' ;
42305 if ( oTextarea.tabIndex ) {
42306 this.TabIndex = oTextarea.tabIndex ;
42309 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42310 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42311 this.frame = Roo.get(this.getId() + '___Frame')
42314 _getConfigHtml : function()
42318 for ( var o in this.fckconfig ) {
42319 sConfig += sConfig.length > 0 ? '&' : '';
42320 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42323 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42327 _getIFrameHtml : function()
42329 var sFile = 'fckeditor.html' ;
42330 /* no idea what this is about..
42333 if ( (/fcksource=true/i).test( window.top.location.search ) )
42334 sFile = 'fckeditor.original.html' ;
42339 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42340 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42343 var html = '<iframe id="' + this.getId() +
42344 '___Frame" src="' + sLink +
42345 '" width="' + this.width +
42346 '" height="' + this.height + '"' +
42347 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42348 ' frameborder="0" scrolling="no"></iframe>' ;
42353 _insertHtmlBefore : function( html, element )
42355 if ( element.insertAdjacentHTML ) {
42357 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42359 var oRange = document.createRange() ;
42360 oRange.setStartBefore( element ) ;
42361 var oFragment = oRange.createContextualFragment( html );
42362 element.parentNode.insertBefore( oFragment, element ) ;
42375 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42377 function FCKeditor_OnComplete(editorInstance){
42378 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42379 f.fckEditor = editorInstance;
42380 //console.log("loaded");
42381 f.fireEvent('editorinit', f, editorInstance);
42401 //<script type="text/javascript">
42403 * @class Roo.form.GridField
42404 * @extends Roo.form.Field
42405 * Embed a grid (or editable grid into a form)
42408 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42410 * xgrid.store = Roo.data.Store
42411 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42412 * xgrid.store.reader = Roo.data.JsonReader
42416 * Creates a new GridField
42417 * @param {Object} config Configuration options
42419 Roo.form.GridField = function(config){
42420 Roo.form.GridField.superclass.constructor.call(this, config);
42424 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42426 * @cfg {Number} width - used to restrict width of grid..
42430 * @cfg {Number} height - used to restrict height of grid..
42434 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42440 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42441 * {tag: "input", type: "checkbox", autocomplete: "off"})
42443 // defaultAutoCreate : { tag: 'div' },
42444 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42446 * @cfg {String} addTitle Text to include for adding a title.
42450 onResize : function(){
42451 Roo.form.Field.superclass.onResize.apply(this, arguments);
42454 initEvents : function(){
42455 // Roo.form.Checkbox.superclass.initEvents.call(this);
42456 // has no events...
42461 getResizeEl : function(){
42465 getPositionEl : function(){
42470 onRender : function(ct, position){
42472 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42473 var style = this.style;
42476 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42477 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42478 this.viewEl = this.wrap.createChild({ tag: 'div' });
42480 this.viewEl.applyStyles(style);
42483 this.viewEl.setWidth(this.width);
42486 this.viewEl.setHeight(this.height);
42488 //if(this.inputValue !== undefined){
42489 //this.setValue(this.value);
42492 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42495 this.grid.render();
42496 this.grid.getDataSource().on('remove', this.refreshValue, this);
42497 this.grid.getDataSource().on('update', this.refreshValue, this);
42498 this.grid.on('afteredit', this.refreshValue, this);
42504 * Sets the value of the item.
42505 * @param {String} either an object or a string..
42507 setValue : function(v){
42509 v = v || []; // empty set..
42510 // this does not seem smart - it really only affects memoryproxy grids..
42511 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42512 var ds = this.grid.getDataSource();
42513 // assumes a json reader..
42515 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42516 ds.loadData( data);
42518 Roo.form.GridField.superclass.setValue.call(this, v);
42519 this.refreshValue();
42520 // should load data in the grid really....
42524 refreshValue: function() {
42526 this.grid.getDataSource().each(function(r) {
42529 this.el.dom.value = Roo.encode(val);
42537 * Ext JS Library 1.1.1
42538 * Copyright(c) 2006-2007, Ext JS, LLC.
42540 * Originally Released Under LGPL - original licence link has changed is not relivant.
42543 * <script type="text/javascript">
42546 * @class Roo.form.DisplayField
42547 * @extends Roo.form.Field
42548 * A generic Field to display non-editable data.
42550 * Creates a new Display Field item.
42551 * @param {Object} config Configuration options
42553 Roo.form.DisplayField = function(config){
42554 Roo.form.DisplayField.superclass.constructor.call(this, config);
42558 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42559 inputType: 'hidden',
42565 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42567 focusClass : undefined,
42569 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42571 fieldClass: 'x-form-field',
42574 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42576 valueRenderer: undefined,
42580 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42581 * {tag: "input", type: "checkbox", autocomplete: "off"})
42584 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42586 onResize : function(){
42587 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42591 initEvents : function(){
42592 // Roo.form.Checkbox.superclass.initEvents.call(this);
42593 // has no events...
42598 getResizeEl : function(){
42602 getPositionEl : function(){
42607 onRender : function(ct, position){
42609 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42610 //if(this.inputValue !== undefined){
42611 this.wrap = this.el.wrap();
42613 this.viewEl = this.wrap.createChild({ tag: 'div'});
42615 if (this.bodyStyle) {
42616 this.viewEl.applyStyles(this.bodyStyle);
42618 //this.viewEl.setStyle('padding', '2px');
42620 this.setValue(this.value);
42625 initValue : Roo.emptyFn,
42630 onClick : function(){
42635 * Sets the checked state of the checkbox.
42636 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42638 setValue : function(v){
42640 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42641 // this might be called before we have a dom element..
42642 if (!this.viewEl) {
42645 this.viewEl.dom.innerHTML = html;
42646 Roo.form.DisplayField.superclass.setValue.call(this, v);
42649 });//<script type="text/javasscript">
42653 * @class Roo.DDView
42654 * A DnD enabled version of Roo.View.
42655 * @param {Element/String} container The Element in which to create the View.
42656 * @param {String} tpl The template string used to create the markup for each element of the View
42657 * @param {Object} config The configuration properties. These include all the config options of
42658 * {@link Roo.View} plus some specific to this class.<br>
42660 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42661 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42663 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42664 .x-view-drag-insert-above {
42665 border-top:1px dotted #3366cc;
42667 .x-view-drag-insert-below {
42668 border-bottom:1px dotted #3366cc;
42674 Roo.DDView = function(container, tpl, config) {
42675 Roo.DDView.superclass.constructor.apply(this, arguments);
42676 this.getEl().setStyle("outline", "0px none");
42677 this.getEl().unselectable();
42678 if (this.dragGroup) {
42679 this.setDraggable(this.dragGroup.split(","));
42681 if (this.dropGroup) {
42682 this.setDroppable(this.dropGroup.split(","));
42684 if (this.deletable) {
42685 this.setDeletable();
42687 this.isDirtyFlag = false;
42693 Roo.extend(Roo.DDView, Roo.View, {
42694 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42695 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42696 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42697 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42701 reset: Roo.emptyFn,
42703 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42705 validate: function() {
42709 destroy: function() {
42710 this.purgeListeners();
42711 this.getEl.removeAllListeners();
42712 this.getEl().remove();
42713 if (this.dragZone) {
42714 if (this.dragZone.destroy) {
42715 this.dragZone.destroy();
42718 if (this.dropZone) {
42719 if (this.dropZone.destroy) {
42720 this.dropZone.destroy();
42725 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
42726 getName: function() {
42730 /** Loads the View from a JSON string representing the Records to put into the Store. */
42731 setValue: function(v) {
42733 throw "DDView.setValue(). DDView must be constructed with a valid Store";
42736 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
42737 this.store.proxy = new Roo.data.MemoryProxy(data);
42741 /** @return {String} a parenthesised list of the ids of the Records in the View. */
42742 getValue: function() {
42744 this.store.each(function(rec) {
42745 result += rec.id + ',';
42747 return result.substr(0, result.length - 1) + ')';
42750 getIds: function() {
42751 var i = 0, result = new Array(this.store.getCount());
42752 this.store.each(function(rec) {
42753 result[i++] = rec.id;
42758 isDirty: function() {
42759 return this.isDirtyFlag;
42763 * Part of the Roo.dd.DropZone interface. If no target node is found, the
42764 * whole Element becomes the target, and this causes the drop gesture to append.
42766 getTargetFromEvent : function(e) {
42767 var target = e.getTarget();
42768 while ((target !== null) && (target.parentNode != this.el.dom)) {
42769 target = target.parentNode;
42772 target = this.el.dom.lastChild || this.el.dom;
42778 * Create the drag data which consists of an object which has the property "ddel" as
42779 * the drag proxy element.
42781 getDragData : function(e) {
42782 var target = this.findItemFromChild(e.getTarget());
42784 this.handleSelection(e);
42785 var selNodes = this.getSelectedNodes();
42788 copy: this.copy || (this.allowCopy && e.ctrlKey),
42792 var selectedIndices = this.getSelectedIndexes();
42793 for (var i = 0; i < selectedIndices.length; i++) {
42794 dragData.records.push(this.store.getAt(selectedIndices[i]));
42796 if (selNodes.length == 1) {
42797 dragData.ddel = target.cloneNode(true); // the div element
42799 var div = document.createElement('div'); // create the multi element drag "ghost"
42800 div.className = 'multi-proxy';
42801 for (var i = 0, len = selNodes.length; i < len; i++) {
42802 div.appendChild(selNodes[i].cloneNode(true));
42804 dragData.ddel = div;
42806 //console.log(dragData)
42807 //console.log(dragData.ddel.innerHTML)
42810 //console.log('nodragData')
42814 /** Specify to which ddGroup items in this DDView may be dragged. */
42815 setDraggable: function(ddGroup) {
42816 if (ddGroup instanceof Array) {
42817 Roo.each(ddGroup, this.setDraggable, this);
42820 if (this.dragZone) {
42821 this.dragZone.addToGroup(ddGroup);
42823 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
42824 containerScroll: true,
42828 // Draggability implies selection. DragZone's mousedown selects the element.
42829 if (!this.multiSelect) { this.singleSelect = true; }
42831 // Wire the DragZone's handlers up to methods in *this*
42832 this.dragZone.getDragData = this.getDragData.createDelegate(this);
42836 /** Specify from which ddGroup this DDView accepts drops. */
42837 setDroppable: function(ddGroup) {
42838 if (ddGroup instanceof Array) {
42839 Roo.each(ddGroup, this.setDroppable, this);
42842 if (this.dropZone) {
42843 this.dropZone.addToGroup(ddGroup);
42845 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
42846 containerScroll: true,
42850 // Wire the DropZone's handlers up to methods in *this*
42851 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
42852 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
42853 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
42854 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
42855 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
42859 /** Decide whether to drop above or below a View node. */
42860 getDropPoint : function(e, n, dd){
42861 if (n == this.el.dom) { return "above"; }
42862 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
42863 var c = t + (b - t) / 2;
42864 var y = Roo.lib.Event.getPageY(e);
42872 onNodeEnter : function(n, dd, e, data){
42876 onNodeOver : function(n, dd, e, data){
42877 var pt = this.getDropPoint(e, n, dd);
42878 // set the insert point style on the target node
42879 var dragElClass = this.dropNotAllowed;
42882 if (pt == "above"){
42883 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
42884 targetElClass = "x-view-drag-insert-above";
42886 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
42887 targetElClass = "x-view-drag-insert-below";
42889 if (this.lastInsertClass != targetElClass){
42890 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
42891 this.lastInsertClass = targetElClass;
42894 return dragElClass;
42897 onNodeOut : function(n, dd, e, data){
42898 this.removeDropIndicators(n);
42901 onNodeDrop : function(n, dd, e, data){
42902 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
42905 var pt = this.getDropPoint(e, n, dd);
42906 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
42907 if (pt == "below") { insertAt++; }
42908 for (var i = 0; i < data.records.length; i++) {
42909 var r = data.records[i];
42910 var dup = this.store.getById(r.id);
42911 if (dup && (dd != this.dragZone)) {
42912 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
42915 this.store.insert(insertAt++, r.copy());
42917 data.source.isDirtyFlag = true;
42919 this.store.insert(insertAt++, r);
42921 this.isDirtyFlag = true;
42924 this.dragZone.cachedTarget = null;
42928 removeDropIndicators : function(n){
42930 Roo.fly(n).removeClass([
42931 "x-view-drag-insert-above",
42932 "x-view-drag-insert-below"]);
42933 this.lastInsertClass = "_noclass";
42938 * Utility method. Add a delete option to the DDView's context menu.
42939 * @param {String} imageUrl The URL of the "delete" icon image.
42941 setDeletable: function(imageUrl) {
42942 if (!this.singleSelect && !this.multiSelect) {
42943 this.singleSelect = true;
42945 var c = this.getContextMenu();
42946 this.contextMenu.on("itemclick", function(item) {
42949 this.remove(this.getSelectedIndexes());
42953 this.contextMenu.add({
42960 /** Return the context menu for this DDView. */
42961 getContextMenu: function() {
42962 if (!this.contextMenu) {
42963 // Create the View's context menu
42964 this.contextMenu = new Roo.menu.Menu({
42965 id: this.id + "-contextmenu"
42967 this.el.on("contextmenu", this.showContextMenu, this);
42969 return this.contextMenu;
42972 disableContextMenu: function() {
42973 if (this.contextMenu) {
42974 this.el.un("contextmenu", this.showContextMenu, this);
42978 showContextMenu: function(e, item) {
42979 item = this.findItemFromChild(e.getTarget());
42982 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
42983 this.contextMenu.showAt(e.getXY());
42988 * Remove {@link Roo.data.Record}s at the specified indices.
42989 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42991 remove: function(selectedIndices) {
42992 selectedIndices = [].concat(selectedIndices);
42993 for (var i = 0; i < selectedIndices.length; i++) {
42994 var rec = this.store.getAt(selectedIndices[i]);
42995 this.store.remove(rec);
43000 * Double click fires the event, but also, if this is draggable, and there is only one other
43001 * related DropZone, it transfers the selected node.
43003 onDblClick : function(e){
43004 var item = this.findItemFromChild(e.getTarget());
43006 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
43009 if (this.dragGroup) {
43010 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
43011 while (targets.indexOf(this.dropZone) > -1) {
43012 targets.remove(this.dropZone);
43014 if (targets.length == 1) {
43015 this.dragZone.cachedTarget = null;
43016 var el = Roo.get(targets[0].getEl());
43017 var box = el.getBox(true);
43018 targets[0].onNodeDrop(el.dom, {
43020 xy: [box.x, box.y + box.height - 1]
43021 }, null, this.getDragData(e));
43027 handleSelection: function(e) {
43028 this.dragZone.cachedTarget = null;
43029 var item = this.findItemFromChild(e.getTarget());
43031 this.clearSelections(true);
43034 if (item && (this.multiSelect || this.singleSelect)){
43035 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
43036 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
43037 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
43038 this.unselect(item);
43040 this.select(item, this.multiSelect && e.ctrlKey);
43041 this.lastSelection = item;
43046 onItemClick : function(item, index, e){
43047 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43053 unselect : function(nodeInfo, suppressEvent){
43054 var node = this.getNode(nodeInfo);
43055 if(node && this.isSelected(node)){
43056 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43057 Roo.fly(node).removeClass(this.selectedClass);
43058 this.selections.remove(node);
43059 if(!suppressEvent){
43060 this.fireEvent("selectionchange", this, this.selections);
43068 * Ext JS Library 1.1.1
43069 * Copyright(c) 2006-2007, Ext JS, LLC.
43071 * Originally Released Under LGPL - original licence link has changed is not relivant.
43074 * <script type="text/javascript">
43078 * @class Roo.LayoutManager
43079 * @extends Roo.util.Observable
43080 * Base class for layout managers.
43082 Roo.LayoutManager = function(container, config){
43083 Roo.LayoutManager.superclass.constructor.call(this);
43084 this.el = Roo.get(container);
43085 // ie scrollbar fix
43086 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43087 document.body.scroll = "no";
43088 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43089 this.el.position('relative');
43091 this.id = this.el.id;
43092 this.el.addClass("x-layout-container");
43093 /** false to disable window resize monitoring @type Boolean */
43094 this.monitorWindowResize = true;
43099 * Fires when a layout is performed.
43100 * @param {Roo.LayoutManager} this
43104 * @event regionresized
43105 * Fires when the user resizes a region.
43106 * @param {Roo.LayoutRegion} region The resized region
43107 * @param {Number} newSize The new size (width for east/west, height for north/south)
43109 "regionresized" : true,
43111 * @event regioncollapsed
43112 * Fires when a region is collapsed.
43113 * @param {Roo.LayoutRegion} region The collapsed region
43115 "regioncollapsed" : true,
43117 * @event regionexpanded
43118 * Fires when a region is expanded.
43119 * @param {Roo.LayoutRegion} region The expanded region
43121 "regionexpanded" : true
43123 this.updating = false;
43124 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43127 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43129 * Returns true if this layout is currently being updated
43130 * @return {Boolean}
43132 isUpdating : function(){
43133 return this.updating;
43137 * Suspend the LayoutManager from doing auto-layouts while
43138 * making multiple add or remove calls
43140 beginUpdate : function(){
43141 this.updating = true;
43145 * Restore auto-layouts and optionally disable the manager from performing a layout
43146 * @param {Boolean} noLayout true to disable a layout update
43148 endUpdate : function(noLayout){
43149 this.updating = false;
43155 layout: function(){
43159 onRegionResized : function(region, newSize){
43160 this.fireEvent("regionresized", region, newSize);
43164 onRegionCollapsed : function(region){
43165 this.fireEvent("regioncollapsed", region);
43168 onRegionExpanded : function(region){
43169 this.fireEvent("regionexpanded", region);
43173 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43174 * performs box-model adjustments.
43175 * @return {Object} The size as an object {width: (the width), height: (the height)}
43177 getViewSize : function(){
43179 if(this.el.dom != document.body){
43180 size = this.el.getSize();
43182 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43184 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43185 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43190 * Returns the Element this layout is bound to.
43191 * @return {Roo.Element}
43193 getEl : function(){
43198 * Returns the specified region.
43199 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43200 * @return {Roo.LayoutRegion}
43202 getRegion : function(target){
43203 return this.regions[target.toLowerCase()];
43206 onWindowResize : function(){
43207 if(this.monitorWindowResize){
43213 * Ext JS Library 1.1.1
43214 * Copyright(c) 2006-2007, Ext JS, LLC.
43216 * Originally Released Under LGPL - original licence link has changed is not relivant.
43219 * <script type="text/javascript">
43222 * @class Roo.BorderLayout
43223 * @extends Roo.LayoutManager
43224 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43225 * please see: <br><br>
43226 * <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>
43227 * <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>
43230 var layout = new Roo.BorderLayout(document.body, {
43264 preferredTabWidth: 150
43269 var CP = Roo.ContentPanel;
43271 layout.beginUpdate();
43272 layout.add("north", new CP("north", "North"));
43273 layout.add("south", new CP("south", {title: "South", closable: true}));
43274 layout.add("west", new CP("west", {title: "West"}));
43275 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43276 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43277 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43278 layout.getRegion("center").showPanel("center1");
43279 layout.endUpdate();
43282 <b>The container the layout is rendered into can be either the body element or any other element.
43283 If it is not the body element, the container needs to either be an absolute positioned element,
43284 or you will need to add "position:relative" to the css of the container. You will also need to specify
43285 the container size if it is not the body element.</b>
43288 * Create a new BorderLayout
43289 * @param {String/HTMLElement/Element} container The container this layout is bound to
43290 * @param {Object} config Configuration options
43292 Roo.BorderLayout = function(container, config){
43293 config = config || {};
43294 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43295 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43296 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43297 var target = this.factory.validRegions[i];
43298 if(config[target]){
43299 this.addRegion(target, config[target]);
43304 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43306 * Creates and adds a new region if it doesn't already exist.
43307 * @param {String} target The target region key (north, south, east, west or center).
43308 * @param {Object} config The regions config object
43309 * @return {BorderLayoutRegion} The new region
43311 addRegion : function(target, config){
43312 if(!this.regions[target]){
43313 var r = this.factory.create(target, this, config);
43314 this.bindRegion(target, r);
43316 return this.regions[target];
43320 bindRegion : function(name, r){
43321 this.regions[name] = r;
43322 r.on("visibilitychange", this.layout, this);
43323 r.on("paneladded", this.layout, this);
43324 r.on("panelremoved", this.layout, this);
43325 r.on("invalidated", this.layout, this);
43326 r.on("resized", this.onRegionResized, this);
43327 r.on("collapsed", this.onRegionCollapsed, this);
43328 r.on("expanded", this.onRegionExpanded, this);
43332 * Performs a layout update.
43334 layout : function(){
43335 if(this.updating) return;
43336 var size = this.getViewSize();
43337 var w = size.width;
43338 var h = size.height;
43343 //var x = 0, y = 0;
43345 var rs = this.regions;
43346 var north = rs["north"];
43347 var south = rs["south"];
43348 var west = rs["west"];
43349 var east = rs["east"];
43350 var center = rs["center"];
43351 //if(this.hideOnLayout){ // not supported anymore
43352 //c.el.setStyle("display", "none");
43354 if(north && north.isVisible()){
43355 var b = north.getBox();
43356 var m = north.getMargins();
43357 b.width = w - (m.left+m.right);
43360 centerY = b.height + b.y + m.bottom;
43361 centerH -= centerY;
43362 north.updateBox(this.safeBox(b));
43364 if(south && south.isVisible()){
43365 var b = south.getBox();
43366 var m = south.getMargins();
43367 b.width = w - (m.left+m.right);
43369 var totalHeight = (b.height + m.top + m.bottom);
43370 b.y = h - totalHeight + m.top;
43371 centerH -= totalHeight;
43372 south.updateBox(this.safeBox(b));
43374 if(west && west.isVisible()){
43375 var b = west.getBox();
43376 var m = west.getMargins();
43377 b.height = centerH - (m.top+m.bottom);
43379 b.y = centerY + m.top;
43380 var totalWidth = (b.width + m.left + m.right);
43381 centerX += totalWidth;
43382 centerW -= totalWidth;
43383 west.updateBox(this.safeBox(b));
43385 if(east && east.isVisible()){
43386 var b = east.getBox();
43387 var m = east.getMargins();
43388 b.height = centerH - (m.top+m.bottom);
43389 var totalWidth = (b.width + m.left + m.right);
43390 b.x = w - totalWidth + m.left;
43391 b.y = centerY + m.top;
43392 centerW -= totalWidth;
43393 east.updateBox(this.safeBox(b));
43396 var m = center.getMargins();
43398 x: centerX + m.left,
43399 y: centerY + m.top,
43400 width: centerW - (m.left+m.right),
43401 height: centerH - (m.top+m.bottom)
43403 //if(this.hideOnLayout){
43404 //center.el.setStyle("display", "block");
43406 center.updateBox(this.safeBox(centerBox));
43409 this.fireEvent("layout", this);
43413 safeBox : function(box){
43414 box.width = Math.max(0, box.width);
43415 box.height = Math.max(0, box.height);
43420 * Adds a ContentPanel (or subclass) to this layout.
43421 * @param {String} target The target region key (north, south, east, west or center).
43422 * @param {Roo.ContentPanel} panel The panel to add
43423 * @return {Roo.ContentPanel} The added panel
43425 add : function(target, panel){
43427 target = target.toLowerCase();
43428 return this.regions[target].add(panel);
43432 * Remove a ContentPanel (or subclass) to this layout.
43433 * @param {String} target The target region key (north, south, east, west or center).
43434 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43435 * @return {Roo.ContentPanel} The removed panel
43437 remove : function(target, panel){
43438 target = target.toLowerCase();
43439 return this.regions[target].remove(panel);
43443 * Searches all regions for a panel with the specified id
43444 * @param {String} panelId
43445 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43447 findPanel : function(panelId){
43448 var rs = this.regions;
43449 for(var target in rs){
43450 if(typeof rs[target] != "function"){
43451 var p = rs[target].getPanel(panelId);
43461 * Searches all regions for a panel with the specified id and activates (shows) it.
43462 * @param {String/ContentPanel} panelId The panels id or the panel itself
43463 * @return {Roo.ContentPanel} The shown panel or null
43465 showPanel : function(panelId) {
43466 var rs = this.regions;
43467 for(var target in rs){
43468 var r = rs[target];
43469 if(typeof r != "function"){
43470 if(r.hasPanel(panelId)){
43471 return r.showPanel(panelId);
43479 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43480 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43482 restoreState : function(provider){
43484 provider = Roo.state.Manager;
43486 var sm = new Roo.LayoutStateManager();
43487 sm.init(this, provider);
43491 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43492 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43493 * a valid ContentPanel config object. Example:
43495 // Create the main layout
43496 var layout = new Roo.BorderLayout('main-ct', {
43507 // Create and add multiple ContentPanels at once via configs
43510 id: 'source-files',
43512 title:'Ext Source Files',
43525 * @param {Object} regions An object containing ContentPanel configs by region name
43527 batchAdd : function(regions){
43528 this.beginUpdate();
43529 for(var rname in regions){
43530 var lr = this.regions[rname];
43532 this.addTypedPanels(lr, regions[rname]);
43539 addTypedPanels : function(lr, ps){
43540 if(typeof ps == 'string'){
43541 lr.add(new Roo.ContentPanel(ps));
43543 else if(ps instanceof Array){
43544 for(var i =0, len = ps.length; i < len; i++){
43545 this.addTypedPanels(lr, ps[i]);
43548 else if(!ps.events){ // raw config?
43550 delete ps.el; // prevent conflict
43551 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43553 else { // panel object assumed!
43558 * Adds a xtype elements to the layout.
43562 xtype : 'ContentPanel',
43569 xtype : 'NestedLayoutPanel',
43575 items : [ ... list of content panels or nested layout panels.. ]
43579 * @param {Object} cfg Xtype definition of item to add.
43581 addxtype : function(cfg)
43583 // basically accepts a pannel...
43584 // can accept a layout region..!?!?
43585 // console.log('BorderLayout add ' + cfg.xtype)
43587 if (!cfg.xtype.match(/Panel$/)) {
43591 var region = cfg.region;
43597 xitems = cfg.items;
43604 case 'ContentPanel': // ContentPanel (el, cfg)
43605 case 'ScrollPanel': // ContentPanel (el, cfg)
43606 if(cfg.autoCreate) {
43607 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43609 var el = this.el.createChild();
43610 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43613 this.add(region, ret);
43617 case 'TreePanel': // our new panel!
43618 cfg.el = this.el.createChild();
43619 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43620 this.add(region, ret);
43623 case 'NestedLayoutPanel':
43624 // create a new Layout (which is a Border Layout...
43625 var el = this.el.createChild();
43626 var clayout = cfg.layout;
43628 clayout.items = clayout.items || [];
43629 // replace this exitems with the clayout ones..
43630 xitems = clayout.items;
43633 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43634 cfg.background = false;
43636 var layout = new Roo.BorderLayout(el, clayout);
43638 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43639 //console.log('adding nested layout panel ' + cfg.toSource());
43640 this.add(region, ret);
43646 // needs grid and region
43648 //var el = this.getRegion(region).el.createChild();
43649 var el = this.el.createChild();
43650 // create the grid first...
43652 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43654 if (region == 'center' && this.active ) {
43655 cfg.background = false;
43657 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43659 this.add(region, ret);
43660 if (cfg.background) {
43661 ret.on('activate', function(gp) {
43662 if (!gp.grid.rendered) {
43675 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43677 // GridPanel (grid, cfg)
43680 this.beginUpdate();
43682 Roo.each(xitems, function(i) {
43692 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43693 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43694 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43695 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43698 var CP = Roo.ContentPanel;
43700 var layout = Roo.BorderLayout.create({
43704 panels: [new CP("north", "North")]
43713 panels: [new CP("west", {title: "West"})]
43722 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
43731 panels: [new CP("south", {title: "South", closable: true})]
43738 preferredTabWidth: 150,
43740 new CP("center1", {title: "Close Me", closable: true}),
43741 new CP("center2", {title: "Center Panel", closable: false})
43746 layout.getRegion("center").showPanel("center1");
43751 Roo.BorderLayout.create = function(config, targetEl){
43752 var layout = new Roo.BorderLayout(targetEl || document.body, config);
43753 layout.beginUpdate();
43754 var regions = Roo.BorderLayout.RegionFactory.validRegions;
43755 for(var j = 0, jlen = regions.length; j < jlen; j++){
43756 var lr = regions[j];
43757 if(layout.regions[lr] && config[lr].panels){
43758 var r = layout.regions[lr];
43759 var ps = config[lr].panels;
43760 layout.addTypedPanels(r, ps);
43763 layout.endUpdate();
43768 Roo.BorderLayout.RegionFactory = {
43770 validRegions : ["north","south","east","west","center"],
43773 create : function(target, mgr, config){
43774 target = target.toLowerCase();
43775 if(config.lightweight || config.basic){
43776 return new Roo.BasicLayoutRegion(mgr, config, target);
43780 return new Roo.NorthLayoutRegion(mgr, config);
43782 return new Roo.SouthLayoutRegion(mgr, config);
43784 return new Roo.EastLayoutRegion(mgr, config);
43786 return new Roo.WestLayoutRegion(mgr, config);
43788 return new Roo.CenterLayoutRegion(mgr, config);
43790 throw 'Layout region "'+target+'" not supported.';
43794 * Ext JS Library 1.1.1
43795 * Copyright(c) 2006-2007, Ext JS, LLC.
43797 * Originally Released Under LGPL - original licence link has changed is not relivant.
43800 * <script type="text/javascript">
43804 * @class Roo.BasicLayoutRegion
43805 * @extends Roo.util.Observable
43806 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
43807 * and does not have a titlebar, tabs or any other features. All it does is size and position
43808 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
43810 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
43812 this.position = pos;
43815 * @scope Roo.BasicLayoutRegion
43819 * @event beforeremove
43820 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
43821 * @param {Roo.LayoutRegion} this
43822 * @param {Roo.ContentPanel} panel The panel
43823 * @param {Object} e The cancel event object
43825 "beforeremove" : true,
43827 * @event invalidated
43828 * Fires when the layout for this region is changed.
43829 * @param {Roo.LayoutRegion} this
43831 "invalidated" : true,
43833 * @event visibilitychange
43834 * Fires when this region is shown or hidden
43835 * @param {Roo.LayoutRegion} this
43836 * @param {Boolean} visibility true or false
43838 "visibilitychange" : true,
43840 * @event paneladded
43841 * Fires when a panel is added.
43842 * @param {Roo.LayoutRegion} this
43843 * @param {Roo.ContentPanel} panel The panel
43845 "paneladded" : true,
43847 * @event panelremoved
43848 * Fires when a panel is removed.
43849 * @param {Roo.LayoutRegion} this
43850 * @param {Roo.ContentPanel} panel The panel
43852 "panelremoved" : true,
43855 * Fires when this region is collapsed.
43856 * @param {Roo.LayoutRegion} this
43858 "collapsed" : true,
43861 * Fires when this region is expanded.
43862 * @param {Roo.LayoutRegion} this
43867 * Fires when this region is slid into view.
43868 * @param {Roo.LayoutRegion} this
43870 "slideshow" : true,
43873 * Fires when this region slides out of view.
43874 * @param {Roo.LayoutRegion} this
43876 "slidehide" : true,
43878 * @event panelactivated
43879 * Fires when a panel is activated.
43880 * @param {Roo.LayoutRegion} this
43881 * @param {Roo.ContentPanel} panel The activated panel
43883 "panelactivated" : true,
43886 * Fires when the user resizes this region.
43887 * @param {Roo.LayoutRegion} this
43888 * @param {Number} newSize The new size (width for east/west, height for north/south)
43892 /** A collection of panels in this region. @type Roo.util.MixedCollection */
43893 this.panels = new Roo.util.MixedCollection();
43894 this.panels.getKey = this.getPanelId.createDelegate(this);
43896 this.activePanel = null;
43897 // ensure listeners are added...
43899 if (config.listeners || config.events) {
43900 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
43901 listeners : config.listeners || {},
43902 events : config.events || {}
43906 if(skipConfig !== true){
43907 this.applyConfig(config);
43911 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
43912 getPanelId : function(p){
43916 applyConfig : function(config){
43917 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43918 this.config = config;
43923 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
43924 * the width, for horizontal (north, south) the height.
43925 * @param {Number} newSize The new width or height
43927 resizeTo : function(newSize){
43928 var el = this.el ? this.el :
43929 (this.activePanel ? this.activePanel.getEl() : null);
43931 switch(this.position){
43934 el.setWidth(newSize);
43935 this.fireEvent("resized", this, newSize);
43939 el.setHeight(newSize);
43940 this.fireEvent("resized", this, newSize);
43946 getBox : function(){
43947 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
43950 getMargins : function(){
43951 return this.margins;
43954 updateBox : function(box){
43956 var el = this.activePanel.getEl();
43957 el.dom.style.left = box.x + "px";
43958 el.dom.style.top = box.y + "px";
43959 this.activePanel.setSize(box.width, box.height);
43963 * Returns the container element for this region.
43964 * @return {Roo.Element}
43966 getEl : function(){
43967 return this.activePanel;
43971 * Returns true if this region is currently visible.
43972 * @return {Boolean}
43974 isVisible : function(){
43975 return this.activePanel ? true : false;
43978 setActivePanel : function(panel){
43979 panel = this.getPanel(panel);
43980 if(this.activePanel && this.activePanel != panel){
43981 this.activePanel.setActiveState(false);
43982 this.activePanel.getEl().setLeftTop(-10000,-10000);
43984 this.activePanel = panel;
43985 panel.setActiveState(true);
43987 panel.setSize(this.box.width, this.box.height);
43989 this.fireEvent("panelactivated", this, panel);
43990 this.fireEvent("invalidated");
43994 * Show the specified panel.
43995 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43996 * @return {Roo.ContentPanel} The shown panel or null
43998 showPanel : function(panel){
43999 if(panel = this.getPanel(panel)){
44000 this.setActivePanel(panel);
44006 * Get the active panel for this region.
44007 * @return {Roo.ContentPanel} The active panel or null
44009 getActivePanel : function(){
44010 return this.activePanel;
44014 * Add the passed ContentPanel(s)
44015 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44016 * @return {Roo.ContentPanel} The panel added (if only one was added)
44018 add : function(panel){
44019 if(arguments.length > 1){
44020 for(var i = 0, len = arguments.length; i < len; i++) {
44021 this.add(arguments[i]);
44025 if(this.hasPanel(panel)){
44026 this.showPanel(panel);
44029 var el = panel.getEl();
44030 if(el.dom.parentNode != this.mgr.el.dom){
44031 this.mgr.el.dom.appendChild(el.dom);
44033 if(panel.setRegion){
44034 panel.setRegion(this);
44036 this.panels.add(panel);
44037 el.setStyle("position", "absolute");
44038 if(!panel.background){
44039 this.setActivePanel(panel);
44040 if(this.config.initialSize && this.panels.getCount()==1){
44041 this.resizeTo(this.config.initialSize);
44044 this.fireEvent("paneladded", this, panel);
44049 * Returns true if the panel is in this region.
44050 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44051 * @return {Boolean}
44053 hasPanel : function(panel){
44054 if(typeof panel == "object"){ // must be panel obj
44055 panel = panel.getId();
44057 return this.getPanel(panel) ? true : false;
44061 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44062 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44063 * @param {Boolean} preservePanel Overrides the config preservePanel option
44064 * @return {Roo.ContentPanel} The panel that was removed
44066 remove : function(panel, preservePanel){
44067 panel = this.getPanel(panel);
44072 this.fireEvent("beforeremove", this, panel, e);
44073 if(e.cancel === true){
44076 var panelId = panel.getId();
44077 this.panels.removeKey(panelId);
44082 * Returns the panel specified or null if it's not in this region.
44083 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44084 * @return {Roo.ContentPanel}
44086 getPanel : function(id){
44087 if(typeof id == "object"){ // must be panel obj
44090 return this.panels.get(id);
44094 * Returns this regions position (north/south/east/west/center).
44097 getPosition: function(){
44098 return this.position;
44102 * Ext JS Library 1.1.1
44103 * Copyright(c) 2006-2007, Ext JS, LLC.
44105 * Originally Released Under LGPL - original licence link has changed is not relivant.
44108 * <script type="text/javascript">
44112 * @class Roo.LayoutRegion
44113 * @extends Roo.BasicLayoutRegion
44114 * This class represents a region in a layout manager.
44115 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44116 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44117 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44118 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44119 * @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})
44120 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44121 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44122 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44123 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44124 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44125 * @cfg {String} title The title for the region (overrides panel titles)
44126 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44127 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44128 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44129 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44130 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44131 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44132 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44133 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44134 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44135 * @cfg {Boolean} showPin True to show a pin button
44136 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44137 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44138 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44139 * @cfg {Number} width For East/West panels
44140 * @cfg {Number} height For North/South panels
44141 * @cfg {Boolean} split To show the splitter
44143 Roo.LayoutRegion = function(mgr, config, pos){
44144 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44145 var dh = Roo.DomHelper;
44146 /** This region's container element
44147 * @type Roo.Element */
44148 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44149 /** This region's title element
44150 * @type Roo.Element */
44152 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44153 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44154 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44156 this.titleEl.enableDisplayMode();
44157 /** This region's title text element
44158 * @type HTMLElement */
44159 this.titleTextEl = this.titleEl.dom.firstChild;
44160 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44161 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44162 this.closeBtn.enableDisplayMode();
44163 this.closeBtn.on("click", this.closeClicked, this);
44164 this.closeBtn.hide();
44166 this.createBody(config);
44167 this.visible = true;
44168 this.collapsed = false;
44170 if(config.hideWhenEmpty){
44172 this.on("paneladded", this.validateVisibility, this);
44173 this.on("panelremoved", this.validateVisibility, this);
44175 this.applyConfig(config);
44178 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44180 createBody : function(){
44181 /** This region's body element
44182 * @type Roo.Element */
44183 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44186 applyConfig : function(c){
44187 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44188 var dh = Roo.DomHelper;
44189 if(c.titlebar !== false){
44190 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44191 this.collapseBtn.on("click", this.collapse, this);
44192 this.collapseBtn.enableDisplayMode();
44194 if(c.showPin === true || this.showPin){
44195 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44196 this.stickBtn.enableDisplayMode();
44197 this.stickBtn.on("click", this.expand, this);
44198 this.stickBtn.hide();
44201 /** This region's collapsed element
44202 * @type Roo.Element */
44203 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44204 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44206 if(c.floatable !== false){
44207 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44208 this.collapsedEl.on("click", this.collapseClick, this);
44211 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44212 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44213 id: "message", unselectable: "on", style:{"float":"left"}});
44214 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44216 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44217 this.expandBtn.on("click", this.expand, this);
44219 if(this.collapseBtn){
44220 this.collapseBtn.setVisible(c.collapsible == true);
44222 this.cmargins = c.cmargins || this.cmargins ||
44223 (this.position == "west" || this.position == "east" ?
44224 {top: 0, left: 2, right:2, bottom: 0} :
44225 {top: 2, left: 0, right:0, bottom: 2});
44226 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44227 this.bottomTabs = c.tabPosition != "top";
44228 this.autoScroll = c.autoScroll || false;
44229 if(this.autoScroll){
44230 this.bodyEl.setStyle("overflow", "auto");
44232 this.bodyEl.setStyle("overflow", "hidden");
44234 //if(c.titlebar !== false){
44235 if((!c.titlebar && !c.title) || c.titlebar === false){
44236 this.titleEl.hide();
44238 this.titleEl.show();
44240 this.titleTextEl.innerHTML = c.title;
44244 this.duration = c.duration || .30;
44245 this.slideDuration = c.slideDuration || .45;
44248 this.collapse(true);
44255 * Returns true if this region is currently visible.
44256 * @return {Boolean}
44258 isVisible : function(){
44259 return this.visible;
44263 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44264 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44266 setCollapsedTitle : function(title){
44267 title = title || " ";
44268 if(this.collapsedTitleTextEl){
44269 this.collapsedTitleTextEl.innerHTML = title;
44273 getBox : function(){
44275 if(!this.collapsed){
44276 b = this.el.getBox(false, true);
44278 b = this.collapsedEl.getBox(false, true);
44283 getMargins : function(){
44284 return this.collapsed ? this.cmargins : this.margins;
44287 highlight : function(){
44288 this.el.addClass("x-layout-panel-dragover");
44291 unhighlight : function(){
44292 this.el.removeClass("x-layout-panel-dragover");
44295 updateBox : function(box){
44297 if(!this.collapsed){
44298 this.el.dom.style.left = box.x + "px";
44299 this.el.dom.style.top = box.y + "px";
44300 this.updateBody(box.width, box.height);
44302 this.collapsedEl.dom.style.left = box.x + "px";
44303 this.collapsedEl.dom.style.top = box.y + "px";
44304 this.collapsedEl.setSize(box.width, box.height);
44307 this.tabs.autoSizeTabs();
44311 updateBody : function(w, h){
44313 this.el.setWidth(w);
44314 w -= this.el.getBorderWidth("rl");
44315 if(this.config.adjustments){
44316 w += this.config.adjustments[0];
44320 this.el.setHeight(h);
44321 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44322 h -= this.el.getBorderWidth("tb");
44323 if(this.config.adjustments){
44324 h += this.config.adjustments[1];
44326 this.bodyEl.setHeight(h);
44328 h = this.tabs.syncHeight(h);
44331 if(this.panelSize){
44332 w = w !== null ? w : this.panelSize.width;
44333 h = h !== null ? h : this.panelSize.height;
44335 if(this.activePanel){
44336 var el = this.activePanel.getEl();
44337 w = w !== null ? w : el.getWidth();
44338 h = h !== null ? h : el.getHeight();
44339 this.panelSize = {width: w, height: h};
44340 this.activePanel.setSize(w, h);
44342 if(Roo.isIE && this.tabs){
44343 this.tabs.el.repaint();
44348 * Returns the container element for this region.
44349 * @return {Roo.Element}
44351 getEl : function(){
44356 * Hides this region.
44359 if(!this.collapsed){
44360 this.el.dom.style.left = "-2000px";
44363 this.collapsedEl.dom.style.left = "-2000px";
44364 this.collapsedEl.hide();
44366 this.visible = false;
44367 this.fireEvent("visibilitychange", this, false);
44371 * Shows this region if it was previously hidden.
44374 if(!this.collapsed){
44377 this.collapsedEl.show();
44379 this.visible = true;
44380 this.fireEvent("visibilitychange", this, true);
44383 closeClicked : function(){
44384 if(this.activePanel){
44385 this.remove(this.activePanel);
44389 collapseClick : function(e){
44391 e.stopPropagation();
44394 e.stopPropagation();
44400 * Collapses this region.
44401 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44403 collapse : function(skipAnim){
44404 if(this.collapsed) return;
44405 this.collapsed = true;
44407 this.split.el.hide();
44409 if(this.config.animate && skipAnim !== true){
44410 this.fireEvent("invalidated", this);
44411 this.animateCollapse();
44413 this.el.setLocation(-20000,-20000);
44415 this.collapsedEl.show();
44416 this.fireEvent("collapsed", this);
44417 this.fireEvent("invalidated", this);
44421 animateCollapse : function(){
44426 * Expands this region if it was previously collapsed.
44427 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44428 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44430 expand : function(e, skipAnim){
44431 if(e) e.stopPropagation();
44432 if(!this.collapsed || this.el.hasActiveFx()) return;
44434 this.afterSlideIn();
44437 this.collapsed = false;
44438 if(this.config.animate && skipAnim !== true){
44439 this.animateExpand();
44443 this.split.el.show();
44445 this.collapsedEl.setLocation(-2000,-2000);
44446 this.collapsedEl.hide();
44447 this.fireEvent("invalidated", this);
44448 this.fireEvent("expanded", this);
44452 animateExpand : function(){
44456 initTabs : function(){
44457 this.bodyEl.setStyle("overflow", "hidden");
44458 var ts = new Roo.TabPanel(this.bodyEl.dom, {
44459 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44460 disableTooltips: this.config.disableTabTips
44462 if(this.config.hideTabs){
44463 ts.stripWrap.setDisplayed(false);
44466 ts.resizeTabs = this.config.resizeTabs === true;
44467 ts.minTabWidth = this.config.minTabWidth || 40;
44468 ts.maxTabWidth = this.config.maxTabWidth || 250;
44469 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44470 ts.monitorResize = false;
44471 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44472 ts.bodyEl.addClass('x-layout-tabs-body');
44473 this.panels.each(this.initPanelAsTab, this);
44476 initPanelAsTab : function(panel){
44477 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44478 this.config.closeOnTab && panel.isClosable());
44479 if(panel.tabTip !== undefined){
44480 ti.setTooltip(panel.tabTip);
44482 ti.on("activate", function(){
44483 this.setActivePanel(panel);
44485 if(this.config.closeOnTab){
44486 ti.on("beforeclose", function(t, e){
44488 this.remove(panel);
44494 updatePanelTitle : function(panel, title){
44495 if(this.activePanel == panel){
44496 this.updateTitle(title);
44499 var ti = this.tabs.getTab(panel.getEl().id);
44501 if(panel.tabTip !== undefined){
44502 ti.setTooltip(panel.tabTip);
44507 updateTitle : function(title){
44508 if(this.titleTextEl && !this.config.title){
44509 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44513 setActivePanel : function(panel){
44514 panel = this.getPanel(panel);
44515 if(this.activePanel && this.activePanel != panel){
44516 this.activePanel.setActiveState(false);
44518 this.activePanel = panel;
44519 panel.setActiveState(true);
44520 if(this.panelSize){
44521 panel.setSize(this.panelSize.width, this.panelSize.height);
44524 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44526 this.updateTitle(panel.getTitle());
44528 this.fireEvent("invalidated", this);
44530 this.fireEvent("panelactivated", this, panel);
44534 * Shows the specified panel.
44535 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44536 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44538 showPanel : function(panel){
44539 if(panel = this.getPanel(panel)){
44541 var tab = this.tabs.getTab(panel.getEl().id);
44542 if(tab.isHidden()){
44543 this.tabs.unhideTab(tab.id);
44547 this.setActivePanel(panel);
44554 * Get the active panel for this region.
44555 * @return {Roo.ContentPanel} The active panel or null
44557 getActivePanel : function(){
44558 return this.activePanel;
44561 validateVisibility : function(){
44562 if(this.panels.getCount() < 1){
44563 this.updateTitle(" ");
44564 this.closeBtn.hide();
44567 if(!this.isVisible()){
44574 * Adds the passed ContentPanel(s) to this region.
44575 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44576 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44578 add : function(panel){
44579 if(arguments.length > 1){
44580 for(var i = 0, len = arguments.length; i < len; i++) {
44581 this.add(arguments[i]);
44585 if(this.hasPanel(panel)){
44586 this.showPanel(panel);
44589 panel.setRegion(this);
44590 this.panels.add(panel);
44591 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44592 this.bodyEl.dom.appendChild(panel.getEl().dom);
44593 if(panel.background !== true){
44594 this.setActivePanel(panel);
44596 this.fireEvent("paneladded", this, panel);
44602 this.initPanelAsTab(panel);
44604 if(panel.background !== true){
44605 this.tabs.activate(panel.getEl().id);
44607 this.fireEvent("paneladded", this, panel);
44612 * Hides the tab for the specified panel.
44613 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44615 hidePanel : function(panel){
44616 if(this.tabs && (panel = this.getPanel(panel))){
44617 this.tabs.hideTab(panel.getEl().id);
44622 * Unhides the tab for a previously hidden panel.
44623 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44625 unhidePanel : function(panel){
44626 if(this.tabs && (panel = this.getPanel(panel))){
44627 this.tabs.unhideTab(panel.getEl().id);
44631 clearPanels : function(){
44632 while(this.panels.getCount() > 0){
44633 this.remove(this.panels.first());
44638 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44639 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44640 * @param {Boolean} preservePanel Overrides the config preservePanel option
44641 * @return {Roo.ContentPanel} The panel that was removed
44643 remove : function(panel, preservePanel){
44644 panel = this.getPanel(panel);
44649 this.fireEvent("beforeremove", this, panel, e);
44650 if(e.cancel === true){
44653 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44654 var panelId = panel.getId();
44655 this.panels.removeKey(panelId);
44657 document.body.appendChild(panel.getEl().dom);
44660 this.tabs.removeTab(panel.getEl().id);
44661 }else if (!preservePanel){
44662 this.bodyEl.dom.removeChild(panel.getEl().dom);
44664 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44665 var p = this.panels.first();
44666 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44667 tempEl.appendChild(p.getEl().dom);
44668 this.bodyEl.update("");
44669 this.bodyEl.dom.appendChild(p.getEl().dom);
44671 this.updateTitle(p.getTitle());
44673 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44674 this.setActivePanel(p);
44676 panel.setRegion(null);
44677 if(this.activePanel == panel){
44678 this.activePanel = null;
44680 if(this.config.autoDestroy !== false && preservePanel !== true){
44681 try{panel.destroy();}catch(e){}
44683 this.fireEvent("panelremoved", this, panel);
44688 * Returns the TabPanel component used by this region
44689 * @return {Roo.TabPanel}
44691 getTabs : function(){
44695 createTool : function(parentEl, className){
44696 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44697 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44698 btn.addClassOnOver("x-layout-tools-button-over");
44703 * Ext JS Library 1.1.1
44704 * Copyright(c) 2006-2007, Ext JS, LLC.
44706 * Originally Released Under LGPL - original licence link has changed is not relivant.
44709 * <script type="text/javascript">
44715 * @class Roo.SplitLayoutRegion
44716 * @extends Roo.LayoutRegion
44717 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44719 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
44720 this.cursor = cursor;
44721 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
44724 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
44725 splitTip : "Drag to resize.",
44726 collapsibleSplitTip : "Drag to resize. Double click to hide.",
44727 useSplitTips : false,
44729 applyConfig : function(config){
44730 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
44733 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
44734 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
44735 /** The SplitBar for this region
44736 * @type Roo.SplitBar */
44737 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
44738 this.split.on("moved", this.onSplitMove, this);
44739 this.split.useShim = config.useShim === true;
44740 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
44741 if(this.useSplitTips){
44742 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
44744 if(config.collapsible){
44745 this.split.el.on("dblclick", this.collapse, this);
44748 if(typeof config.minSize != "undefined"){
44749 this.split.minSize = config.minSize;
44751 if(typeof config.maxSize != "undefined"){
44752 this.split.maxSize = config.maxSize;
44754 if(config.hideWhenEmpty || config.hidden || config.collapsed){
44755 this.hideSplitter();
44760 getHMaxSize : function(){
44761 var cmax = this.config.maxSize || 10000;
44762 var center = this.mgr.getRegion("center");
44763 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
44766 getVMaxSize : function(){
44767 var cmax = this.config.maxSize || 10000;
44768 var center = this.mgr.getRegion("center");
44769 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
44772 onSplitMove : function(split, newSize){
44773 this.fireEvent("resized", this, newSize);
44777 * Returns the {@link Roo.SplitBar} for this region.
44778 * @return {Roo.SplitBar}
44780 getSplitBar : function(){
44785 this.hideSplitter();
44786 Roo.SplitLayoutRegion.superclass.hide.call(this);
44789 hideSplitter : function(){
44791 this.split.el.setLocation(-2000,-2000);
44792 this.split.el.hide();
44798 this.split.el.show();
44800 Roo.SplitLayoutRegion.superclass.show.call(this);
44803 beforeSlide: function(){
44804 if(Roo.isGecko){// firefox overflow auto bug workaround
44805 this.bodyEl.clip();
44806 if(this.tabs) this.tabs.bodyEl.clip();
44807 if(this.activePanel){
44808 this.activePanel.getEl().clip();
44810 if(this.activePanel.beforeSlide){
44811 this.activePanel.beforeSlide();
44817 afterSlide : function(){
44818 if(Roo.isGecko){// firefox overflow auto bug workaround
44819 this.bodyEl.unclip();
44820 if(this.tabs) this.tabs.bodyEl.unclip();
44821 if(this.activePanel){
44822 this.activePanel.getEl().unclip();
44823 if(this.activePanel.afterSlide){
44824 this.activePanel.afterSlide();
44830 initAutoHide : function(){
44831 if(this.autoHide !== false){
44832 if(!this.autoHideHd){
44833 var st = new Roo.util.DelayedTask(this.slideIn, this);
44834 this.autoHideHd = {
44835 "mouseout": function(e){
44836 if(!e.within(this.el, true)){
44840 "mouseover" : function(e){
44846 this.el.on(this.autoHideHd);
44850 clearAutoHide : function(){
44851 if(this.autoHide !== false){
44852 this.el.un("mouseout", this.autoHideHd.mouseout);
44853 this.el.un("mouseover", this.autoHideHd.mouseover);
44857 clearMonitor : function(){
44858 Roo.get(document).un("click", this.slideInIf, this);
44861 // these names are backwards but not changed for compat
44862 slideOut : function(){
44863 if(this.isSlid || this.el.hasActiveFx()){
44866 this.isSlid = true;
44867 if(this.collapseBtn){
44868 this.collapseBtn.hide();
44870 this.closeBtnState = this.closeBtn.getStyle('display');
44871 this.closeBtn.hide();
44873 this.stickBtn.show();
44876 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
44877 this.beforeSlide();
44878 this.el.setStyle("z-index", 10001);
44879 this.el.slideIn(this.getSlideAnchor(), {
44880 callback: function(){
44882 this.initAutoHide();
44883 Roo.get(document).on("click", this.slideInIf, this);
44884 this.fireEvent("slideshow", this);
44891 afterSlideIn : function(){
44892 this.clearAutoHide();
44893 this.isSlid = false;
44894 this.clearMonitor();
44895 this.el.setStyle("z-index", "");
44896 if(this.collapseBtn){
44897 this.collapseBtn.show();
44899 this.closeBtn.setStyle('display', this.closeBtnState);
44901 this.stickBtn.hide();
44903 this.fireEvent("slidehide", this);
44906 slideIn : function(cb){
44907 if(!this.isSlid || this.el.hasActiveFx()){
44911 this.isSlid = false;
44912 this.beforeSlide();
44913 this.el.slideOut(this.getSlideAnchor(), {
44914 callback: function(){
44915 this.el.setLeftTop(-10000, -10000);
44917 this.afterSlideIn();
44925 slideInIf : function(e){
44926 if(!e.within(this.el)){
44931 animateCollapse : function(){
44932 this.beforeSlide();
44933 this.el.setStyle("z-index", 20000);
44934 var anchor = this.getSlideAnchor();
44935 this.el.slideOut(anchor, {
44936 callback : function(){
44937 this.el.setStyle("z-index", "");
44938 this.collapsedEl.slideIn(anchor, {duration:.3});
44940 this.el.setLocation(-10000,-10000);
44942 this.fireEvent("collapsed", this);
44949 animateExpand : function(){
44950 this.beforeSlide();
44951 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
44952 this.el.setStyle("z-index", 20000);
44953 this.collapsedEl.hide({
44956 this.el.slideIn(this.getSlideAnchor(), {
44957 callback : function(){
44958 this.el.setStyle("z-index", "");
44961 this.split.el.show();
44963 this.fireEvent("invalidated", this);
44964 this.fireEvent("expanded", this);
44992 getAnchor : function(){
44993 return this.anchors[this.position];
44996 getCollapseAnchor : function(){
44997 return this.canchors[this.position];
45000 getSlideAnchor : function(){
45001 return this.sanchors[this.position];
45004 getAlignAdj : function(){
45005 var cm = this.cmargins;
45006 switch(this.position){
45022 getExpandAdj : function(){
45023 var c = this.collapsedEl, cm = this.cmargins;
45024 switch(this.position){
45026 return [-(cm.right+c.getWidth()+cm.left), 0];
45029 return [cm.right+c.getWidth()+cm.left, 0];
45032 return [0, -(cm.top+cm.bottom+c.getHeight())];
45035 return [0, cm.top+cm.bottom+c.getHeight()];
45041 * Ext JS Library 1.1.1
45042 * Copyright(c) 2006-2007, Ext JS, LLC.
45044 * Originally Released Under LGPL - original licence link has changed is not relivant.
45047 * <script type="text/javascript">
45050 * These classes are private internal classes
45052 Roo.CenterLayoutRegion = function(mgr, config){
45053 Roo.LayoutRegion.call(this, mgr, config, "center");
45054 this.visible = true;
45055 this.minWidth = config.minWidth || 20;
45056 this.minHeight = config.minHeight || 20;
45059 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45061 // center panel can't be hidden
45065 // center panel can't be hidden
45068 getMinWidth: function(){
45069 return this.minWidth;
45072 getMinHeight: function(){
45073 return this.minHeight;
45078 Roo.NorthLayoutRegion = function(mgr, config){
45079 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45081 this.split.placement = Roo.SplitBar.TOP;
45082 this.split.orientation = Roo.SplitBar.VERTICAL;
45083 this.split.el.addClass("x-layout-split-v");
45085 var size = config.initialSize || config.height;
45086 if(typeof size != "undefined"){
45087 this.el.setHeight(size);
45090 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45091 orientation: Roo.SplitBar.VERTICAL,
45092 getBox : function(){
45093 if(this.collapsed){
45094 return this.collapsedEl.getBox();
45096 var box = this.el.getBox();
45098 box.height += this.split.el.getHeight();
45103 updateBox : function(box){
45104 if(this.split && !this.collapsed){
45105 box.height -= this.split.el.getHeight();
45106 this.split.el.setLeft(box.x);
45107 this.split.el.setTop(box.y+box.height);
45108 this.split.el.setWidth(box.width);
45110 if(this.collapsed){
45111 this.updateBody(box.width, null);
45113 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45117 Roo.SouthLayoutRegion = function(mgr, config){
45118 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45120 this.split.placement = Roo.SplitBar.BOTTOM;
45121 this.split.orientation = Roo.SplitBar.VERTICAL;
45122 this.split.el.addClass("x-layout-split-v");
45124 var size = config.initialSize || config.height;
45125 if(typeof size != "undefined"){
45126 this.el.setHeight(size);
45129 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45130 orientation: Roo.SplitBar.VERTICAL,
45131 getBox : function(){
45132 if(this.collapsed){
45133 return this.collapsedEl.getBox();
45135 var box = this.el.getBox();
45137 var sh = this.split.el.getHeight();
45144 updateBox : function(box){
45145 if(this.split && !this.collapsed){
45146 var sh = this.split.el.getHeight();
45149 this.split.el.setLeft(box.x);
45150 this.split.el.setTop(box.y-sh);
45151 this.split.el.setWidth(box.width);
45153 if(this.collapsed){
45154 this.updateBody(box.width, null);
45156 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45160 Roo.EastLayoutRegion = function(mgr, config){
45161 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45163 this.split.placement = Roo.SplitBar.RIGHT;
45164 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45165 this.split.el.addClass("x-layout-split-h");
45167 var size = config.initialSize || config.width;
45168 if(typeof size != "undefined"){
45169 this.el.setWidth(size);
45172 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45173 orientation: Roo.SplitBar.HORIZONTAL,
45174 getBox : function(){
45175 if(this.collapsed){
45176 return this.collapsedEl.getBox();
45178 var box = this.el.getBox();
45180 var sw = this.split.el.getWidth();
45187 updateBox : function(box){
45188 if(this.split && !this.collapsed){
45189 var sw = this.split.el.getWidth();
45191 this.split.el.setLeft(box.x);
45192 this.split.el.setTop(box.y);
45193 this.split.el.setHeight(box.height);
45196 if(this.collapsed){
45197 this.updateBody(null, box.height);
45199 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45203 Roo.WestLayoutRegion = function(mgr, config){
45204 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45206 this.split.placement = Roo.SplitBar.LEFT;
45207 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45208 this.split.el.addClass("x-layout-split-h");
45210 var size = config.initialSize || config.width;
45211 if(typeof size != "undefined"){
45212 this.el.setWidth(size);
45215 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45216 orientation: Roo.SplitBar.HORIZONTAL,
45217 getBox : function(){
45218 if(this.collapsed){
45219 return this.collapsedEl.getBox();
45221 var box = this.el.getBox();
45223 box.width += this.split.el.getWidth();
45228 updateBox : function(box){
45229 if(this.split && !this.collapsed){
45230 var sw = this.split.el.getWidth();
45232 this.split.el.setLeft(box.x+box.width);
45233 this.split.el.setTop(box.y);
45234 this.split.el.setHeight(box.height);
45236 if(this.collapsed){
45237 this.updateBody(null, box.height);
45239 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45244 * Ext JS Library 1.1.1
45245 * Copyright(c) 2006-2007, Ext JS, LLC.
45247 * Originally Released Under LGPL - original licence link has changed is not relivant.
45250 * <script type="text/javascript">
45255 * Private internal class for reading and applying state
45257 Roo.LayoutStateManager = function(layout){
45258 // default empty state
45267 Roo.LayoutStateManager.prototype = {
45268 init : function(layout, provider){
45269 this.provider = provider;
45270 var state = provider.get(layout.id+"-layout-state");
45272 var wasUpdating = layout.isUpdating();
45274 layout.beginUpdate();
45276 for(var key in state){
45277 if(typeof state[key] != "function"){
45278 var rstate = state[key];
45279 var r = layout.getRegion(key);
45282 r.resizeTo(rstate.size);
45284 if(rstate.collapsed == true){
45287 r.expand(null, true);
45293 layout.endUpdate();
45295 this.state = state;
45297 this.layout = layout;
45298 layout.on("regionresized", this.onRegionResized, this);
45299 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45300 layout.on("regionexpanded", this.onRegionExpanded, this);
45303 storeState : function(){
45304 this.provider.set(this.layout.id+"-layout-state", this.state);
45307 onRegionResized : function(region, newSize){
45308 this.state[region.getPosition()].size = newSize;
45312 onRegionCollapsed : function(region){
45313 this.state[region.getPosition()].collapsed = true;
45317 onRegionExpanded : function(region){
45318 this.state[region.getPosition()].collapsed = false;
45323 * Ext JS Library 1.1.1
45324 * Copyright(c) 2006-2007, Ext JS, LLC.
45326 * Originally Released Under LGPL - original licence link has changed is not relivant.
45329 * <script type="text/javascript">
45332 * @class Roo.ContentPanel
45333 * @extends Roo.util.Observable
45334 * A basic ContentPanel element.
45335 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45336 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45337 * @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
45338 * @cfg {Boolean} closable True if the panel can be closed/removed
45339 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45340 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45341 * @cfg {Toolbar} toolbar A toolbar for this panel
45342 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45343 * @cfg {String} title The title for this panel
45344 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45345 * @cfg {String} url Calls {@link #setUrl} with this value
45346 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45347 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45348 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45350 * Create a new ContentPanel.
45351 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45352 * @param {String/Object} config A string to set only the title or a config object
45353 * @param {String} content (optional) Set the HTML content for this panel
45354 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45356 Roo.ContentPanel = function(el, config, content){
45360 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45364 if (config && config.parentLayout) {
45365 el = config.parentLayout.el.createChild();
45368 if(el.autoCreate){ // xtype is available if this is called from factory
45372 this.el = Roo.get(el);
45373 if(!this.el && config && config.autoCreate){
45374 if(typeof config.autoCreate == "object"){
45375 if(!config.autoCreate.id){
45376 config.autoCreate.id = config.id||el;
45378 this.el = Roo.DomHelper.append(document.body,
45379 config.autoCreate, true);
45381 this.el = Roo.DomHelper.append(document.body,
45382 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45385 this.closable = false;
45386 this.loaded = false;
45387 this.active = false;
45388 if(typeof config == "string"){
45389 this.title = config;
45391 Roo.apply(this, config);
45394 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45395 this.wrapEl = this.el.wrap();
45396 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45403 this.resizeEl = Roo.get(this.resizeEl, true);
45405 this.resizeEl = this.el;
45410 * Fires when this panel is activated.
45411 * @param {Roo.ContentPanel} this
45415 * @event deactivate
45416 * Fires when this panel is activated.
45417 * @param {Roo.ContentPanel} this
45419 "deactivate" : true,
45423 * Fires when this panel is resized if fitToFrame is true.
45424 * @param {Roo.ContentPanel} this
45425 * @param {Number} width The width after any component adjustments
45426 * @param {Number} height The height after any component adjustments
45430 if(this.autoScroll){
45431 this.resizeEl.setStyle("overflow", "auto");
45433 // fix randome scrolling
45434 this.el.on('scroll', function() {
45435 this.scrollTo('top',0);
45438 content = content || this.content;
45440 this.setContent(content);
45442 if(config && config.url){
45443 this.setUrl(this.url, this.params, this.loadOnce);
45448 Roo.ContentPanel.superclass.constructor.call(this);
45451 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45453 setRegion : function(region){
45454 this.region = region;
45456 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45458 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45463 * Returns the toolbar for this Panel if one was configured.
45464 * @return {Roo.Toolbar}
45466 getToolbar : function(){
45467 return this.toolbar;
45470 setActiveState : function(active){
45471 this.active = active;
45473 this.fireEvent("deactivate", this);
45475 this.fireEvent("activate", this);
45479 * Updates this panel's element
45480 * @param {String} content The new content
45481 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45483 setContent : function(content, loadScripts){
45484 this.el.update(content, loadScripts);
45487 ignoreResize : function(w, h){
45488 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45491 this.lastSize = {width: w, height: h};
45496 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45497 * @return {Roo.UpdateManager} The UpdateManager
45499 getUpdateManager : function(){
45500 return this.el.getUpdateManager();
45503 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45504 * @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:
45507 url: "your-url.php",
45508 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45509 callback: yourFunction,
45510 scope: yourObject, //(optional scope)
45513 text: "Loading...",
45518 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45519 * 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.
45520 * @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}
45521 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45522 * @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.
45523 * @return {Roo.ContentPanel} this
45526 var um = this.el.getUpdateManager();
45527 um.update.apply(um, arguments);
45533 * 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.
45534 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45535 * @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)
45536 * @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)
45537 * @return {Roo.UpdateManager} The UpdateManager
45539 setUrl : function(url, params, loadOnce){
45540 if(this.refreshDelegate){
45541 this.removeListener("activate", this.refreshDelegate);
45543 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45544 this.on("activate", this.refreshDelegate);
45545 return this.el.getUpdateManager();
45548 _handleRefresh : function(url, params, loadOnce){
45549 if(!loadOnce || !this.loaded){
45550 var updater = this.el.getUpdateManager();
45551 updater.update(url, params, this._setLoaded.createDelegate(this));
45555 _setLoaded : function(){
45556 this.loaded = true;
45560 * Returns this panel's id
45563 getId : function(){
45568 * Returns this panel's element - used by regiosn to add.
45569 * @return {Roo.Element}
45571 getEl : function(){
45572 return this.wrapEl || this.el;
45575 adjustForComponents : function(width, height){
45576 if(this.resizeEl != this.el){
45577 width -= this.el.getFrameWidth('lr');
45578 height -= this.el.getFrameWidth('tb');
45581 var te = this.toolbar.getEl();
45582 height -= te.getHeight();
45583 te.setWidth(width);
45585 if(this.adjustments){
45586 width += this.adjustments[0];
45587 height += this.adjustments[1];
45589 return {"width": width, "height": height};
45592 setSize : function(width, height){
45593 if(this.fitToFrame && !this.ignoreResize(width, height)){
45594 if(this.fitContainer && this.resizeEl != this.el){
45595 this.el.setSize(width, height);
45597 var size = this.adjustForComponents(width, height);
45598 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45599 this.fireEvent('resize', this, size.width, size.height);
45604 * Returns this panel's title
45607 getTitle : function(){
45612 * Set this panel's title
45613 * @param {String} title
45615 setTitle : function(title){
45616 this.title = title;
45618 this.region.updatePanelTitle(this, title);
45623 * Returns true is this panel was configured to be closable
45624 * @return {Boolean}
45626 isClosable : function(){
45627 return this.closable;
45630 beforeSlide : function(){
45632 this.resizeEl.clip();
45635 afterSlide : function(){
45637 this.resizeEl.unclip();
45641 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45642 * Will fail silently if the {@link #setUrl} method has not been called.
45643 * This does not activate the panel, just updates its content.
45645 refresh : function(){
45646 if(this.refreshDelegate){
45647 this.loaded = false;
45648 this.refreshDelegate();
45653 * Destroys this panel
45655 destroy : function(){
45656 this.el.removeAllListeners();
45657 var tempEl = document.createElement("span");
45658 tempEl.appendChild(this.el.dom);
45659 tempEl.innerHTML = "";
45665 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45675 * @param {Object} cfg Xtype definition of item to add.
45678 addxtype : function(cfg) {
45680 if (cfg.xtype.match(/^Form$/)) {
45681 var el = this.el.createChild();
45683 this.form = new Roo.form.Form(cfg);
45686 if ( this.form.allItems.length) this.form.render(el.dom);
45689 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
45691 cfg.el = this.el.appendChild(document.createElement("div"));
45693 var ret = new Roo[cfg.xtype](cfg);
45694 ret.render(false, ''); // render blank..
45704 * @class Roo.GridPanel
45705 * @extends Roo.ContentPanel
45707 * Create a new GridPanel.
45708 * @param {Roo.grid.Grid} grid The grid for this panel
45709 * @param {String/Object} config A string to set only the panel's title, or a config object
45711 Roo.GridPanel = function(grid, config){
45714 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45715 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45717 this.wrapper.dom.appendChild(grid.getGridEl().dom);
45719 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
45722 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
45724 // xtype created footer. - not sure if will work as we normally have to render first..
45725 if (this.footer && !this.footer.el && this.footer.xtype) {
45727 this.footer.container = this.grid.getView().getFooterPanel(true);
45728 this.footer.dataSource = this.grid.dataSource;
45729 this.footer = Roo.factory(this.footer, Roo);
45733 grid.monitorWindowResize = false; // turn off autosizing
45734 grid.autoHeight = false;
45735 grid.autoWidth = false;
45737 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
45740 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
45741 getId : function(){
45742 return this.grid.id;
45746 * Returns the grid for this panel
45747 * @return {Roo.grid.Grid}
45749 getGrid : function(){
45753 setSize : function(width, height){
45754 if(!this.ignoreResize(width, height)){
45755 var grid = this.grid;
45756 var size = this.adjustForComponents(width, height);
45757 grid.getGridEl().setSize(size.width, size.height);
45762 beforeSlide : function(){
45763 this.grid.getView().scroller.clip();
45766 afterSlide : function(){
45767 this.grid.getView().scroller.unclip();
45770 destroy : function(){
45771 this.grid.destroy();
45773 Roo.GridPanel.superclass.destroy.call(this);
45779 * @class Roo.NestedLayoutPanel
45780 * @extends Roo.ContentPanel
45782 * Create a new NestedLayoutPanel.
45785 * @param {Roo.BorderLayout} layout The layout for this panel
45786 * @param {String/Object} config A string to set only the title or a config object
45788 Roo.NestedLayoutPanel = function(layout, config)
45790 // construct with only one argument..
45791 /* FIXME - implement nicer consturctors
45792 if (layout.layout) {
45794 layout = config.layout;
45795 delete config.layout;
45797 if (layout.xtype && !layout.getEl) {
45798 // then layout needs constructing..
45799 layout = Roo.factory(layout, Roo);
45804 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
45806 layout.monitorWindowResize = false; // turn off autosizing
45807 this.layout = layout;
45808 this.layout.getEl().addClass("x-layout-nested-layout");
45815 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
45817 setSize : function(width, height){
45818 if(!this.ignoreResize(width, height)){
45819 var size = this.adjustForComponents(width, height);
45820 var el = this.layout.getEl();
45821 el.setSize(size.width, size.height);
45822 var touch = el.dom.offsetWidth;
45823 this.layout.layout();
45824 // ie requires a double layout on the first pass
45825 if(Roo.isIE && !this.initialized){
45826 this.initialized = true;
45827 this.layout.layout();
45832 // activate all subpanels if not currently active..
45834 setActiveState : function(active){
45835 this.active = active;
45837 this.fireEvent("deactivate", this);
45841 this.fireEvent("activate", this);
45842 // not sure if this should happen before or after..
45843 if (!this.layout) {
45844 return; // should not happen..
45847 for (var r in this.layout.regions) {
45848 reg = this.layout.getRegion(r);
45849 if (reg.getActivePanel()) {
45850 //reg.showPanel(reg.getActivePanel()); // force it to activate..
45851 reg.setActivePanel(reg.getActivePanel());
45854 if (!reg.panels.length) {
45857 reg.showPanel(reg.getPanel(0));
45866 * Returns the nested BorderLayout for this panel
45867 * @return {Roo.BorderLayout}
45869 getLayout : function(){
45870 return this.layout;
45874 * Adds a xtype elements to the layout of the nested panel
45878 xtype : 'ContentPanel',
45885 xtype : 'NestedLayoutPanel',
45891 items : [ ... list of content panels or nested layout panels.. ]
45895 * @param {Object} cfg Xtype definition of item to add.
45897 addxtype : function(cfg) {
45898 return this.layout.addxtype(cfg);
45903 Roo.ScrollPanel = function(el, config, content){
45904 config = config || {};
45905 config.fitToFrame = true;
45906 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
45908 this.el.dom.style.overflow = "hidden";
45909 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
45910 this.el.removeClass("x-layout-inactive-content");
45911 this.el.on("mousewheel", this.onWheel, this);
45913 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
45914 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
45915 up.unselectable(); down.unselectable();
45916 up.on("click", this.scrollUp, this);
45917 down.on("click", this.scrollDown, this);
45918 up.addClassOnOver("x-scroller-btn-over");
45919 down.addClassOnOver("x-scroller-btn-over");
45920 up.addClassOnClick("x-scroller-btn-click");
45921 down.addClassOnClick("x-scroller-btn-click");
45922 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
45924 this.resizeEl = this.el;
45925 this.el = wrap; this.up = up; this.down = down;
45928 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
45930 wheelIncrement : 5,
45931 scrollUp : function(){
45932 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
45935 scrollDown : function(){
45936 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
45939 afterScroll : function(){
45940 var el = this.resizeEl;
45941 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
45942 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45943 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45946 setSize : function(){
45947 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
45948 this.afterScroll();
45951 onWheel : function(e){
45952 var d = e.getWheelDelta();
45953 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
45954 this.afterScroll();
45958 setContent : function(content, loadScripts){
45959 this.resizeEl.update(content, loadScripts);
45973 * @class Roo.TreePanel
45974 * @extends Roo.ContentPanel
45976 * Create a new TreePanel. - defaults to fit/scoll contents.
45977 * @param {String/Object} config A string to set only the panel's title, or a config object
45978 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
45980 Roo.TreePanel = function(config){
45981 var el = config.el;
45982 var tree = config.tree;
45983 delete config.tree;
45984 delete config.el; // hopefull!
45986 // wrapper for IE7 strict & safari scroll issue
45988 var treeEl = el.createChild();
45989 config.resizeEl = treeEl;
45993 Roo.TreePanel.superclass.constructor.call(this, el, config);
45996 this.tree = new Roo.tree.TreePanel(treeEl , tree);
45997 //console.log(tree);
45998 this.on('activate', function()
46000 if (this.tree.rendered) {
46003 //console.log('render tree');
46004 this.tree.render();
46007 this.on('resize', function (cp, w, h) {
46008 this.tree.innerCt.setWidth(w);
46009 this.tree.innerCt.setHeight(h);
46010 this.tree.innerCt.setStyle('overflow-y', 'auto');
46017 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
46034 * Ext JS Library 1.1.1
46035 * Copyright(c) 2006-2007, Ext JS, LLC.
46037 * Originally Released Under LGPL - original licence link has changed is not relivant.
46040 * <script type="text/javascript">
46045 * @class Roo.ReaderLayout
46046 * @extends Roo.BorderLayout
46047 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46048 * center region containing two nested regions (a top one for a list view and one for item preview below),
46049 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46050 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46051 * expedites the setup of the overall layout and regions for this common application style.
46054 var reader = new Roo.ReaderLayout();
46055 var CP = Roo.ContentPanel; // shortcut for adding
46057 reader.beginUpdate();
46058 reader.add("north", new CP("north", "North"));
46059 reader.add("west", new CP("west", {title: "West"}));
46060 reader.add("east", new CP("east", {title: "East"}));
46062 reader.regions.listView.add(new CP("listView", "List"));
46063 reader.regions.preview.add(new CP("preview", "Preview"));
46064 reader.endUpdate();
46067 * Create a new ReaderLayout
46068 * @param {Object} config Configuration options
46069 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46070 * document.body if omitted)
46072 Roo.ReaderLayout = function(config, renderTo){
46073 var c = config || {size:{}};
46074 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46075 north: c.north !== false ? Roo.apply({
46079 }, c.north) : false,
46080 west: c.west !== false ? Roo.apply({
46088 margins:{left:5,right:0,bottom:5,top:5},
46089 cmargins:{left:5,right:5,bottom:5,top:5}
46090 }, c.west) : false,
46091 east: c.east !== false ? Roo.apply({
46099 margins:{left:0,right:5,bottom:5,top:5},
46100 cmargins:{left:5,right:5,bottom:5,top:5}
46101 }, c.east) : false,
46102 center: Roo.apply({
46103 tabPosition: 'top',
46107 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46111 this.el.addClass('x-reader');
46113 this.beginUpdate();
46115 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46116 south: c.preview !== false ? Roo.apply({
46123 cmargins:{top:5,left:0, right:0, bottom:0}
46124 }, c.preview) : false,
46125 center: Roo.apply({
46131 this.add('center', new Roo.NestedLayoutPanel(inner,
46132 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46136 this.regions.preview = inner.getRegion('south');
46137 this.regions.listView = inner.getRegion('center');
46140 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46142 * Ext JS Library 1.1.1
46143 * Copyright(c) 2006-2007, Ext JS, LLC.
46145 * Originally Released Under LGPL - original licence link has changed is not relivant.
46148 * <script type="text/javascript">
46152 * @class Roo.grid.Grid
46153 * @extends Roo.util.Observable
46154 * This class represents the primary interface of a component based grid control.
46155 * <br><br>Usage:<pre><code>
46156 var grid = new Roo.grid.Grid("my-container-id", {
46159 selModel: mySelectionModel,
46160 autoSizeColumns: true,
46161 monitorWindowResize: false,
46162 trackMouseOver: true
46167 * <b>Common Problems:</b><br/>
46168 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46169 * element will correct this<br/>
46170 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46171 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46172 * are unpredictable.<br/>
46173 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46174 * grid to calculate dimensions/offsets.<br/>
46176 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46177 * The container MUST have some type of size defined for the grid to fill. The container will be
46178 * automatically set to position relative if it isn't already.
46179 * @param {Object} config A config object that sets properties on this grid.
46181 Roo.grid.Grid = function(container, config){
46182 // initialize the container
46183 this.container = Roo.get(container);
46184 this.container.update("");
46185 this.container.setStyle("overflow", "hidden");
46186 this.container.addClass('x-grid-container');
46188 this.id = this.container.id;
46190 Roo.apply(this, config);
46191 // check and correct shorthanded configs
46193 this.dataSource = this.ds;
46197 this.colModel = this.cm;
46201 this.selModel = this.sm;
46205 if (this.selModel) {
46206 this.selModel = Roo.factory(this.selModel, Roo.grid);
46207 this.sm = this.selModel;
46208 this.sm.xmodule = this.xmodule || false;
46210 if (typeof(this.colModel.config) == 'undefined') {
46211 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46212 this.cm = this.colModel;
46213 this.cm.xmodule = this.xmodule || false;
46215 if (this.dataSource) {
46216 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46217 this.ds = this.dataSource;
46218 this.ds.xmodule = this.xmodule || false;
46225 this.container.setWidth(this.width);
46229 this.container.setHeight(this.height);
46236 * The raw click event for the entire grid.
46237 * @param {Roo.EventObject} e
46242 * The raw dblclick event for the entire grid.
46243 * @param {Roo.EventObject} e
46247 * @event contextmenu
46248 * The raw contextmenu event for the entire grid.
46249 * @param {Roo.EventObject} e
46251 "contextmenu" : true,
46254 * The raw mousedown event for the entire grid.
46255 * @param {Roo.EventObject} e
46257 "mousedown" : true,
46260 * The raw mouseup event for the entire grid.
46261 * @param {Roo.EventObject} e
46266 * The raw mouseover event for the entire grid.
46267 * @param {Roo.EventObject} e
46269 "mouseover" : true,
46272 * The raw mouseout event for the entire grid.
46273 * @param {Roo.EventObject} e
46278 * The raw keypress event for the entire grid.
46279 * @param {Roo.EventObject} e
46284 * The raw keydown event for the entire grid.
46285 * @param {Roo.EventObject} e
46293 * Fires when a cell is clicked
46294 * @param {Grid} this
46295 * @param {Number} rowIndex
46296 * @param {Number} columnIndex
46297 * @param {Roo.EventObject} e
46299 "cellclick" : true,
46301 * @event celldblclick
46302 * Fires when a cell is double clicked
46303 * @param {Grid} this
46304 * @param {Number} rowIndex
46305 * @param {Number} columnIndex
46306 * @param {Roo.EventObject} e
46308 "celldblclick" : true,
46311 * Fires when a row is clicked
46312 * @param {Grid} this
46313 * @param {Number} rowIndex
46314 * @param {Roo.EventObject} e
46318 * @event rowdblclick
46319 * Fires when a row is double clicked
46320 * @param {Grid} this
46321 * @param {Number} rowIndex
46322 * @param {Roo.EventObject} e
46324 "rowdblclick" : true,
46326 * @event headerclick
46327 * Fires when a header is clicked
46328 * @param {Grid} this
46329 * @param {Number} columnIndex
46330 * @param {Roo.EventObject} e
46332 "headerclick" : true,
46334 * @event headerdblclick
46335 * Fires when a header cell is double clicked
46336 * @param {Grid} this
46337 * @param {Number} columnIndex
46338 * @param {Roo.EventObject} e
46340 "headerdblclick" : true,
46342 * @event rowcontextmenu
46343 * Fires when a row is right clicked
46344 * @param {Grid} this
46345 * @param {Number} rowIndex
46346 * @param {Roo.EventObject} e
46348 "rowcontextmenu" : true,
46350 * @event cellcontextmenu
46351 * Fires when a cell is right clicked
46352 * @param {Grid} this
46353 * @param {Number} rowIndex
46354 * @param {Number} cellIndex
46355 * @param {Roo.EventObject} e
46357 "cellcontextmenu" : true,
46359 * @event headercontextmenu
46360 * Fires when a header is right clicked
46361 * @param {Grid} this
46362 * @param {Number} columnIndex
46363 * @param {Roo.EventObject} e
46365 "headercontextmenu" : true,
46367 * @event bodyscroll
46368 * Fires when the body element is scrolled
46369 * @param {Number} scrollLeft
46370 * @param {Number} scrollTop
46372 "bodyscroll" : true,
46374 * @event columnresize
46375 * Fires when the user resizes a column
46376 * @param {Number} columnIndex
46377 * @param {Number} newSize
46379 "columnresize" : true,
46381 * @event columnmove
46382 * Fires when the user moves a column
46383 * @param {Number} oldIndex
46384 * @param {Number} newIndex
46386 "columnmove" : true,
46389 * Fires when row(s) start being dragged
46390 * @param {Grid} this
46391 * @param {Roo.GridDD} dd The drag drop object
46392 * @param {event} e The raw browser event
46394 "startdrag" : true,
46397 * Fires when a drag operation is complete
46398 * @param {Grid} this
46399 * @param {Roo.GridDD} dd The drag drop object
46400 * @param {event} e The raw browser event
46405 * Fires when dragged row(s) are dropped on a valid DD target
46406 * @param {Grid} this
46407 * @param {Roo.GridDD} dd The drag drop object
46408 * @param {String} targetId The target drag drop object
46409 * @param {event} e The raw browser event
46414 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46415 * @param {Grid} this
46416 * @param {Roo.GridDD} dd The drag drop object
46417 * @param {String} targetId The target drag drop object
46418 * @param {event} e The raw browser event
46423 * Fires when the dragged row(s) first cross another DD target while being dragged
46424 * @param {Grid} this
46425 * @param {Roo.GridDD} dd The drag drop object
46426 * @param {String} targetId The target drag drop object
46427 * @param {event} e The raw browser event
46429 "dragenter" : true,
46432 * Fires when the dragged row(s) leave another DD target while being dragged
46433 * @param {Grid} this
46434 * @param {Roo.GridDD} dd The drag drop object
46435 * @param {String} targetId The target drag drop object
46436 * @param {event} e The raw browser event
46441 * Fires when the grid is rendered
46442 * @param {Grid} grid
46447 Roo.grid.Grid.superclass.constructor.call(this);
46449 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46452 * @cfg {String} ddGroup - drag drop group.
46456 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46458 minColumnWidth : 25,
46461 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46462 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46463 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46465 autoSizeColumns : false,
46468 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46470 autoSizeHeaders : true,
46473 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46475 monitorWindowResize : true,
46478 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46479 * rows measured to get a columns size. Default is 0 (all rows).
46481 maxRowsToMeasure : 0,
46484 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46486 trackMouseOver : true,
46489 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46493 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46495 enableDragDrop : false,
46498 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46500 enableColumnMove : true,
46503 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46505 enableColumnHide : true,
46508 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46510 enableRowHeightSync : false,
46513 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46518 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46520 autoHeight : false,
46523 * @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.
46525 autoExpandColumn : false,
46528 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46531 autoExpandMin : 50,
46534 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46536 autoExpandMax : 1000,
46539 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46544 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46548 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46555 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46556 * of a fixed width. Default is false.
46559 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46562 * Called once after all setup has been completed and the grid is ready to be rendered.
46563 * @return {Roo.grid.Grid} this
46565 render : function(){
46566 var c = this.container;
46567 // try to detect autoHeight/width mode
46568 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46569 this.autoHeight = true;
46571 var view = this.getView();
46574 c.on("click", this.onClick, this);
46575 c.on("dblclick", this.onDblClick, this);
46576 c.on("contextmenu", this.onContextMenu, this);
46577 c.on("keydown", this.onKeyDown, this);
46579 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46581 this.getSelectionModel().init(this);
46586 this.loadMask = new Roo.LoadMask(this.container,
46587 Roo.apply({store:this.dataSource}, this.loadMask));
46591 if (this.toolbar && this.toolbar.xtype) {
46592 this.toolbar.container = this.getView().getHeaderPanel(true);
46593 this.toolbar = new Ext.Toolbar(this.toolbar);
46595 if (this.footer && this.footer.xtype) {
46596 this.footer.dataSource = this.getDataSource();
46597 this.footer.container = this.getView().getFooterPanel(true);
46598 this.footer = Roo.factory(this.footer, Roo);
46600 if (this.dropTarget && this.dropTarget.xtype) {
46601 delete this.dropTarget.xtype;
46602 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46606 this.rendered = true;
46607 this.fireEvent('render', this);
46612 * Reconfigures the grid to use a different Store and Column Model.
46613 * The View will be bound to the new objects and refreshed.
46614 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46615 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46617 reconfigure : function(dataSource, colModel){
46619 this.loadMask.destroy();
46620 this.loadMask = new Roo.LoadMask(this.container,
46621 Roo.apply({store:dataSource}, this.loadMask));
46623 this.view.bind(dataSource, colModel);
46624 this.dataSource = dataSource;
46625 this.colModel = colModel;
46626 this.view.refresh(true);
46630 onKeyDown : function(e){
46631 this.fireEvent("keydown", e);
46635 * Destroy this grid.
46636 * @param {Boolean} removeEl True to remove the element
46638 destroy : function(removeEl, keepListeners){
46640 this.loadMask.destroy();
46642 var c = this.container;
46643 c.removeAllListeners();
46644 this.view.destroy();
46645 this.colModel.purgeListeners();
46646 if(!keepListeners){
46647 this.purgeListeners();
46650 if(removeEl === true){
46656 processEvent : function(name, e){
46657 this.fireEvent(name, e);
46658 var t = e.getTarget();
46660 var header = v.findHeaderIndex(t);
46661 if(header !== false){
46662 this.fireEvent("header" + name, this, header, e);
46664 var row = v.findRowIndex(t);
46665 var cell = v.findCellIndex(t);
46667 this.fireEvent("row" + name, this, row, e);
46668 if(cell !== false){
46669 this.fireEvent("cell" + name, this, row, cell, e);
46676 onClick : function(e){
46677 this.processEvent("click", e);
46681 onContextMenu : function(e, t){
46682 this.processEvent("contextmenu", e);
46686 onDblClick : function(e){
46687 this.processEvent("dblclick", e);
46691 walkCells : function(row, col, step, fn, scope){
46692 var cm = this.colModel, clen = cm.getColumnCount();
46693 var ds = this.dataSource, rlen = ds.getCount(), first = true;
46705 if(fn.call(scope || this, row, col, cm) === true){
46723 if(fn.call(scope || this, row, col, cm) === true){
46735 getSelections : function(){
46736 return this.selModel.getSelections();
46740 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
46741 * but if manual update is required this method will initiate it.
46743 autoSize : function(){
46745 this.view.layout();
46746 if(this.view.adjustForScroll){
46747 this.view.adjustForScroll();
46753 * Returns the grid's underlying element.
46754 * @return {Element} The element
46756 getGridEl : function(){
46757 return this.container;
46760 // private for compatibility, overridden by editor grid
46761 stopEditing : function(){},
46764 * Returns the grid's SelectionModel.
46765 * @return {SelectionModel}
46767 getSelectionModel : function(){
46768 if(!this.selModel){
46769 this.selModel = new Roo.grid.RowSelectionModel();
46771 return this.selModel;
46775 * Returns the grid's DataSource.
46776 * @return {DataSource}
46778 getDataSource : function(){
46779 return this.dataSource;
46783 * Returns the grid's ColumnModel.
46784 * @return {ColumnModel}
46786 getColumnModel : function(){
46787 return this.colModel;
46791 * Returns the grid's GridView object.
46792 * @return {GridView}
46794 getView : function(){
46796 this.view = new Roo.grid.GridView(this.viewConfig);
46801 * Called to get grid's drag proxy text, by default returns this.ddText.
46804 getDragDropText : function(){
46805 var count = this.selModel.getCount();
46806 return String.format(this.ddText, count, count == 1 ? '' : 's');
46810 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
46811 * %0 is replaced with the number of selected rows.
46814 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
46816 * Ext JS Library 1.1.1
46817 * Copyright(c) 2006-2007, Ext JS, LLC.
46819 * Originally Released Under LGPL - original licence link has changed is not relivant.
46822 * <script type="text/javascript">
46825 Roo.grid.AbstractGridView = function(){
46829 "beforerowremoved" : true,
46830 "beforerowsinserted" : true,
46831 "beforerefresh" : true,
46832 "rowremoved" : true,
46833 "rowsinserted" : true,
46834 "rowupdated" : true,
46837 Roo.grid.AbstractGridView.superclass.constructor.call(this);
46840 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
46841 rowClass : "x-grid-row",
46842 cellClass : "x-grid-cell",
46843 tdClass : "x-grid-td",
46844 hdClass : "x-grid-hd",
46845 splitClass : "x-grid-hd-split",
46847 init: function(grid){
46849 var cid = this.grid.getGridEl().id;
46850 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
46851 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
46852 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
46853 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
46856 getColumnRenderers : function(){
46857 var renderers = [];
46858 var cm = this.grid.colModel;
46859 var colCount = cm.getColumnCount();
46860 for(var i = 0; i < colCount; i++){
46861 renderers[i] = cm.getRenderer(i);
46866 getColumnIds : function(){
46868 var cm = this.grid.colModel;
46869 var colCount = cm.getColumnCount();
46870 for(var i = 0; i < colCount; i++){
46871 ids[i] = cm.getColumnId(i);
46876 getDataIndexes : function(){
46877 if(!this.indexMap){
46878 this.indexMap = this.buildIndexMap();
46880 return this.indexMap.colToData;
46883 getColumnIndexByDataIndex : function(dataIndex){
46884 if(!this.indexMap){
46885 this.indexMap = this.buildIndexMap();
46887 return this.indexMap.dataToCol[dataIndex];
46891 * Set a css style for a column dynamically.
46892 * @param {Number} colIndex The index of the column
46893 * @param {String} name The css property name
46894 * @param {String} value The css value
46896 setCSSStyle : function(colIndex, name, value){
46897 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
46898 Roo.util.CSS.updateRule(selector, name, value);
46901 generateRules : function(cm){
46902 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
46903 Roo.util.CSS.removeStyleSheet(rulesId);
46904 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46905 var cid = cm.getColumnId(i);
46906 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
46907 this.tdSelector, cid, " {\n}\n",
46908 this.hdSelector, cid, " {\n}\n",
46909 this.splitSelector, cid, " {\n}\n");
46911 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46915 * Ext JS Library 1.1.1
46916 * Copyright(c) 2006-2007, Ext JS, LLC.
46918 * Originally Released Under LGPL - original licence link has changed is not relivant.
46921 * <script type="text/javascript">
46925 // This is a support class used internally by the Grid components
46926 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
46928 this.view = grid.getView();
46929 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46930 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
46932 this.setHandleElId(Roo.id(hd));
46933 this.setOuterHandleElId(Roo.id(hd2));
46935 this.scroll = false;
46937 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
46939 getDragData : function(e){
46940 var t = Roo.lib.Event.getTarget(e);
46941 var h = this.view.findHeaderCell(t);
46943 return {ddel: h.firstChild, header:h};
46948 onInitDrag : function(e){
46949 this.view.headersDisabled = true;
46950 var clone = this.dragData.ddel.cloneNode(true);
46951 clone.id = Roo.id();
46952 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
46953 this.proxy.update(clone);
46957 afterValidDrop : function(){
46959 setTimeout(function(){
46960 v.headersDisabled = false;
46964 afterInvalidDrop : function(){
46966 setTimeout(function(){
46967 v.headersDisabled = false;
46973 * Ext JS Library 1.1.1
46974 * Copyright(c) 2006-2007, Ext JS, LLC.
46976 * Originally Released Under LGPL - original licence link has changed is not relivant.
46979 * <script type="text/javascript">
46982 // This is a support class used internally by the Grid components
46983 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
46985 this.view = grid.getView();
46986 // split the proxies so they don't interfere with mouse events
46987 this.proxyTop = Roo.DomHelper.append(document.body, {
46988 cls:"col-move-top", html:" "
46990 this.proxyBottom = Roo.DomHelper.append(document.body, {
46991 cls:"col-move-bottom", html:" "
46993 this.proxyTop.hide = this.proxyBottom.hide = function(){
46994 this.setLeftTop(-100,-100);
46995 this.setStyle("visibility", "hidden");
46997 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46998 // temporarily disabled
46999 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
47000 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
47002 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
47003 proxyOffsets : [-4, -9],
47004 fly: Roo.Element.fly,
47006 getTargetFromEvent : function(e){
47007 var t = Roo.lib.Event.getTarget(e);
47008 var cindex = this.view.findCellIndex(t);
47009 if(cindex !== false){
47010 return this.view.getHeaderCell(cindex);
47014 nextVisible : function(h){
47015 var v = this.view, cm = this.grid.colModel;
47018 if(!cm.isHidden(v.getCellIndex(h))){
47026 prevVisible : function(h){
47027 var v = this.view, cm = this.grid.colModel;
47030 if(!cm.isHidden(v.getCellIndex(h))){
47038 positionIndicator : function(h, n, e){
47039 var x = Roo.lib.Event.getPageX(e);
47040 var r = Roo.lib.Dom.getRegion(n.firstChild);
47041 var px, pt, py = r.top + this.proxyOffsets[1];
47042 if((r.right - x) <= (r.right-r.left)/2){
47043 px = r.right+this.view.borderWidth;
47049 var oldIndex = this.view.getCellIndex(h);
47050 var newIndex = this.view.getCellIndex(n);
47052 if(this.grid.colModel.isFixed(newIndex)){
47056 var locked = this.grid.colModel.isLocked(newIndex);
47061 if(oldIndex < newIndex){
47064 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47067 px += this.proxyOffsets[0];
47068 this.proxyTop.setLeftTop(px, py);
47069 this.proxyTop.show();
47070 if(!this.bottomOffset){
47071 this.bottomOffset = this.view.mainHd.getHeight();
47073 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47074 this.proxyBottom.show();
47078 onNodeEnter : function(n, dd, e, data){
47079 if(data.header != n){
47080 this.positionIndicator(data.header, n, e);
47084 onNodeOver : function(n, dd, e, data){
47085 var result = false;
47086 if(data.header != n){
47087 result = this.positionIndicator(data.header, n, e);
47090 this.proxyTop.hide();
47091 this.proxyBottom.hide();
47093 return result ? this.dropAllowed : this.dropNotAllowed;
47096 onNodeOut : function(n, dd, e, data){
47097 this.proxyTop.hide();
47098 this.proxyBottom.hide();
47101 onNodeDrop : function(n, dd, e, data){
47102 var h = data.header;
47104 var cm = this.grid.colModel;
47105 var x = Roo.lib.Event.getPageX(e);
47106 var r = Roo.lib.Dom.getRegion(n.firstChild);
47107 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47108 var oldIndex = this.view.getCellIndex(h);
47109 var newIndex = this.view.getCellIndex(n);
47110 var locked = cm.isLocked(newIndex);
47114 if(oldIndex < newIndex){
47117 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47120 cm.setLocked(oldIndex, locked, true);
47121 cm.moveColumn(oldIndex, newIndex);
47122 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47130 * Ext JS Library 1.1.1
47131 * Copyright(c) 2006-2007, Ext JS, LLC.
47133 * Originally Released Under LGPL - original licence link has changed is not relivant.
47136 * <script type="text/javascript">
47140 * @class Roo.grid.GridView
47141 * @extends Roo.util.Observable
47144 * @param {Object} config
47146 Roo.grid.GridView = function(config){
47147 Roo.grid.GridView.superclass.constructor.call(this);
47150 Roo.apply(this, config);
47153 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47156 * Override this function to apply custom css classes to rows during rendering
47157 * @param {Record} record The record
47158 * @param {Number} index
47159 * @method getRowClass
47161 rowClass : "x-grid-row",
47163 cellClass : "x-grid-col",
47165 tdClass : "x-grid-td",
47167 hdClass : "x-grid-hd",
47169 splitClass : "x-grid-split",
47171 sortClasses : ["sort-asc", "sort-desc"],
47173 enableMoveAnim : false,
47177 dh : Roo.DomHelper,
47179 fly : Roo.Element.fly,
47181 css : Roo.util.CSS,
47187 scrollIncrement : 22,
47189 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47191 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47193 bind : function(ds, cm){
47195 this.ds.un("load", this.onLoad, this);
47196 this.ds.un("datachanged", this.onDataChange, this);
47197 this.ds.un("add", this.onAdd, this);
47198 this.ds.un("remove", this.onRemove, this);
47199 this.ds.un("update", this.onUpdate, this);
47200 this.ds.un("clear", this.onClear, this);
47203 ds.on("load", this.onLoad, this);
47204 ds.on("datachanged", this.onDataChange, this);
47205 ds.on("add", this.onAdd, this);
47206 ds.on("remove", this.onRemove, this);
47207 ds.on("update", this.onUpdate, this);
47208 ds.on("clear", this.onClear, this);
47213 this.cm.un("widthchange", this.onColWidthChange, this);
47214 this.cm.un("headerchange", this.onHeaderChange, this);
47215 this.cm.un("hiddenchange", this.onHiddenChange, this);
47216 this.cm.un("columnmoved", this.onColumnMove, this);
47217 this.cm.un("columnlockchange", this.onColumnLock, this);
47220 this.generateRules(cm);
47221 cm.on("widthchange", this.onColWidthChange, this);
47222 cm.on("headerchange", this.onHeaderChange, this);
47223 cm.on("hiddenchange", this.onHiddenChange, this);
47224 cm.on("columnmoved", this.onColumnMove, this);
47225 cm.on("columnlockchange", this.onColumnLock, this);
47230 init: function(grid){
47231 Roo.grid.GridView.superclass.init.call(this, grid);
47233 this.bind(grid.dataSource, grid.colModel);
47235 grid.on("headerclick", this.handleHeaderClick, this);
47237 if(grid.trackMouseOver){
47238 grid.on("mouseover", this.onRowOver, this);
47239 grid.on("mouseout", this.onRowOut, this);
47241 grid.cancelTextSelection = function(){};
47242 this.gridId = grid.id;
47244 var tpls = this.templates || {};
47247 tpls.master = new Roo.Template(
47248 '<div class="x-grid" hidefocus="true">',
47249 '<div class="x-grid-topbar"></div>',
47250 '<div class="x-grid-scroller"><div></div></div>',
47251 '<div class="x-grid-locked">',
47252 '<div class="x-grid-header">{lockedHeader}</div>',
47253 '<div class="x-grid-body">{lockedBody}</div>',
47255 '<div class="x-grid-viewport">',
47256 '<div class="x-grid-header">{header}</div>',
47257 '<div class="x-grid-body">{body}</div>',
47259 '<div class="x-grid-bottombar"></div>',
47260 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47261 '<div class="x-grid-resize-proxy"> </div>',
47264 tpls.master.disableformats = true;
47268 tpls.header = new Roo.Template(
47269 '<table border="0" cellspacing="0" cellpadding="0">',
47270 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47273 tpls.header.disableformats = true;
47275 tpls.header.compile();
47278 tpls.hcell = new Roo.Template(
47279 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47280 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47283 tpls.hcell.disableFormats = true;
47285 tpls.hcell.compile();
47288 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47289 tpls.hsplit.disableFormats = true;
47291 tpls.hsplit.compile();
47294 tpls.body = new Roo.Template(
47295 '<table border="0" cellspacing="0" cellpadding="0">',
47296 "<tbody>{rows}</tbody>",
47299 tpls.body.disableFormats = true;
47301 tpls.body.compile();
47304 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47305 tpls.row.disableFormats = true;
47307 tpls.row.compile();
47310 tpls.cell = new Roo.Template(
47311 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47312 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47315 tpls.cell.disableFormats = true;
47317 tpls.cell.compile();
47319 this.templates = tpls;
47322 // remap these for backwards compat
47323 onColWidthChange : function(){
47324 this.updateColumns.apply(this, arguments);
47326 onHeaderChange : function(){
47327 this.updateHeaders.apply(this, arguments);
47329 onHiddenChange : function(){
47330 this.handleHiddenChange.apply(this, arguments);
47332 onColumnMove : function(){
47333 this.handleColumnMove.apply(this, arguments);
47335 onColumnLock : function(){
47336 this.handleLockChange.apply(this, arguments);
47339 onDataChange : function(){
47341 this.updateHeaderSortState();
47344 onClear : function(){
47348 onUpdate : function(ds, record){
47349 this.refreshRow(record);
47352 refreshRow : function(record){
47353 var ds = this.ds, index;
47354 if(typeof record == 'number'){
47356 record = ds.getAt(index);
47358 index = ds.indexOf(record);
47360 this.insertRows(ds, index, index, true);
47361 this.onRemove(ds, record, index+1, true);
47362 this.syncRowHeights(index, index);
47364 this.fireEvent("rowupdated", this, index, record);
47367 onAdd : function(ds, records, index){
47368 this.insertRows(ds, index, index + (records.length-1));
47371 onRemove : function(ds, record, index, isUpdate){
47372 if(isUpdate !== true){
47373 this.fireEvent("beforerowremoved", this, index, record);
47375 var bt = this.getBodyTable(), lt = this.getLockedTable();
47376 if(bt.rows[index]){
47377 bt.firstChild.removeChild(bt.rows[index]);
47379 if(lt.rows[index]){
47380 lt.firstChild.removeChild(lt.rows[index]);
47382 if(isUpdate !== true){
47383 this.stripeRows(index);
47384 this.syncRowHeights(index, index);
47386 this.fireEvent("rowremoved", this, index, record);
47390 onLoad : function(){
47391 this.scrollToTop();
47395 * Scrolls the grid to the top
47397 scrollToTop : function(){
47399 this.scroller.dom.scrollTop = 0;
47405 * Gets a panel in the header of the grid that can be used for toolbars etc.
47406 * After modifying the contents of this panel a call to grid.autoSize() may be
47407 * required to register any changes in size.
47408 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47409 * @return Roo.Element
47411 getHeaderPanel : function(doShow){
47413 this.headerPanel.show();
47415 return this.headerPanel;
47419 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47420 * After modifying the contents of this panel a call to grid.autoSize() may be
47421 * required to register any changes in size.
47422 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47423 * @return Roo.Element
47425 getFooterPanel : function(doShow){
47427 this.footerPanel.show();
47429 return this.footerPanel;
47432 initElements : function(){
47433 var E = Roo.Element;
47434 var el = this.grid.getGridEl().dom.firstChild;
47435 var cs = el.childNodes;
47437 this.el = new E(el);
47438 this.headerPanel = new E(el.firstChild);
47439 this.headerPanel.enableDisplayMode("block");
47441 this.scroller = new E(cs[1]);
47442 this.scrollSizer = new E(this.scroller.dom.firstChild);
47444 this.lockedWrap = new E(cs[2]);
47445 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47446 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47448 this.mainWrap = new E(cs[3]);
47449 this.mainHd = new E(this.mainWrap.dom.firstChild);
47450 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47452 this.footerPanel = new E(cs[4]);
47453 this.footerPanel.enableDisplayMode("block");
47455 this.focusEl = new E(cs[5]);
47456 this.focusEl.swallowEvent("click", true);
47457 this.resizeProxy = new E(cs[6]);
47459 this.headerSelector = String.format(
47460 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47461 this.lockedHd.id, this.mainHd.id
47464 this.splitterSelector = String.format(
47465 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47466 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47469 idToCssName : function(s)
47471 return s.replace(/[^a-z0-9]+/ig, '-');
47474 getHeaderCell : function(index){
47475 return Roo.DomQuery.select(this.headerSelector)[index];
47478 getHeaderCellMeasure : function(index){
47479 return this.getHeaderCell(index).firstChild;
47482 getHeaderCellText : function(index){
47483 return this.getHeaderCell(index).firstChild.firstChild;
47486 getLockedTable : function(){
47487 return this.lockedBody.dom.firstChild;
47490 getBodyTable : function(){
47491 return this.mainBody.dom.firstChild;
47494 getLockedRow : function(index){
47495 return this.getLockedTable().rows[index];
47498 getRow : function(index){
47499 return this.getBodyTable().rows[index];
47502 getRowComposite : function(index){
47504 this.rowEl = new Roo.CompositeElementLite();
47506 var els = [], lrow, mrow;
47507 if(lrow = this.getLockedRow(index)){
47510 if(mrow = this.getRow(index)){
47513 this.rowEl.elements = els;
47517 getCell : function(rowIndex, colIndex){
47518 var locked = this.cm.getLockedCount();
47520 if(colIndex < locked){
47521 source = this.lockedBody.dom.firstChild;
47523 source = this.mainBody.dom.firstChild;
47524 colIndex -= locked;
47526 return source.rows[rowIndex].childNodes[colIndex];
47529 getCellText : function(rowIndex, colIndex){
47530 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47533 getCellBox : function(cell){
47534 var b = this.fly(cell).getBox();
47535 if(Roo.isOpera){ // opera fails to report the Y
47536 b.y = cell.offsetTop + this.mainBody.getY();
47541 getCellIndex : function(cell){
47542 var id = String(cell.className).match(this.cellRE);
47544 return parseInt(id[1], 10);
47549 findHeaderIndex : function(n){
47550 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47551 return r ? this.getCellIndex(r) : false;
47554 findHeaderCell : function(n){
47555 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47556 return r ? r : false;
47559 findRowIndex : function(n){
47563 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47564 return r ? r.rowIndex : false;
47567 findCellIndex : function(node){
47568 var stop = this.el.dom;
47569 while(node && node != stop){
47570 if(this.findRE.test(node.className)){
47571 return this.getCellIndex(node);
47573 node = node.parentNode;
47578 getColumnId : function(index){
47579 return this.cm.getColumnId(index);
47582 getSplitters : function(){
47583 if(this.splitterSelector){
47584 return Roo.DomQuery.select(this.splitterSelector);
47590 getSplitter : function(index){
47591 return this.getSplitters()[index];
47594 onRowOver : function(e, t){
47596 if((row = this.findRowIndex(t)) !== false){
47597 this.getRowComposite(row).addClass("x-grid-row-over");
47601 onRowOut : function(e, t){
47603 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47604 this.getRowComposite(row).removeClass("x-grid-row-over");
47608 renderHeaders : function(){
47610 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47611 var cb = [], lb = [], sb = [], lsb = [], p = {};
47612 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47613 p.cellId = "x-grid-hd-0-" + i;
47614 p.splitId = "x-grid-csplit-0-" + i;
47615 p.id = cm.getColumnId(i);
47616 p.title = cm.getColumnTooltip(i) || "";
47617 p.value = cm.getColumnHeader(i) || "";
47618 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47619 if(!cm.isLocked(i)){
47620 cb[cb.length] = ct.apply(p);
47621 sb[sb.length] = st.apply(p);
47623 lb[lb.length] = ct.apply(p);
47624 lsb[lsb.length] = st.apply(p);
47627 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47628 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47631 updateHeaders : function(){
47632 var html = this.renderHeaders();
47633 this.lockedHd.update(html[0]);
47634 this.mainHd.update(html[1]);
47638 * Focuses the specified row.
47639 * @param {Number} row The row index
47641 focusRow : function(row){
47642 var x = this.scroller.dom.scrollLeft;
47643 this.focusCell(row, 0, false);
47644 this.scroller.dom.scrollLeft = x;
47648 * Focuses the specified cell.
47649 * @param {Number} row The row index
47650 * @param {Number} col The column index
47651 * @param {Boolean} hscroll false to disable horizontal scrolling
47653 focusCell : function(row, col, hscroll){
47654 var el = this.ensureVisible(row, col, hscroll);
47655 this.focusEl.alignTo(el, "tl-tl");
47657 this.focusEl.focus();
47659 this.focusEl.focus.defer(1, this.focusEl);
47664 * Scrolls the specified cell into view
47665 * @param {Number} row The row index
47666 * @param {Number} col The column index
47667 * @param {Boolean} hscroll false to disable horizontal scrolling
47669 ensureVisible : function(row, col, hscroll){
47670 if(typeof row != "number"){
47671 row = row.rowIndex;
47673 if(row < 0 && row >= this.ds.getCount()){
47676 col = (col !== undefined ? col : 0);
47677 var cm = this.grid.colModel;
47678 while(cm.isHidden(col)){
47682 var el = this.getCell(row, col);
47686 var c = this.scroller.dom;
47688 var ctop = parseInt(el.offsetTop, 10);
47689 var cleft = parseInt(el.offsetLeft, 10);
47690 var cbot = ctop + el.offsetHeight;
47691 var cright = cleft + el.offsetWidth;
47693 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47694 var stop = parseInt(c.scrollTop, 10);
47695 var sleft = parseInt(c.scrollLeft, 10);
47696 var sbot = stop + ch;
47697 var sright = sleft + c.clientWidth;
47700 c.scrollTop = ctop;
47701 }else if(cbot > sbot){
47702 c.scrollTop = cbot-ch;
47705 if(hscroll !== false){
47707 c.scrollLeft = cleft;
47708 }else if(cright > sright){
47709 c.scrollLeft = cright-c.clientWidth;
47715 updateColumns : function(){
47716 this.grid.stopEditing();
47717 var cm = this.grid.colModel, colIds = this.getColumnIds();
47718 //var totalWidth = cm.getTotalWidth();
47720 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47721 //if(cm.isHidden(i)) continue;
47722 var w = cm.getColumnWidth(i);
47723 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47724 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47726 this.updateSplitters();
47729 generateRules : function(cm){
47730 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
47731 Roo.util.CSS.removeStyleSheet(rulesId);
47732 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47733 var cid = cm.getColumnId(i);
47735 if(cm.config[i].align){
47736 align = 'text-align:'+cm.config[i].align+';';
47739 if(cm.isHidden(i)){
47740 hidden = 'display:none;';
47742 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
47744 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
47745 this.hdSelector, cid, " {\n", align, width, "}\n",
47746 this.tdSelector, cid, " {\n",hidden,"\n}\n",
47747 this.splitSelector, cid, " {\n", hidden , "\n}\n");
47749 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47752 updateSplitters : function(){
47753 var cm = this.cm, s = this.getSplitters();
47754 if(s){ // splitters not created yet
47755 var pos = 0, locked = true;
47756 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47757 if(cm.isHidden(i)) continue;
47758 var w = cm.getColumnWidth(i);
47759 if(!cm.isLocked(i) && locked){
47764 s[i].style.left = (pos-this.splitOffset) + "px";
47769 handleHiddenChange : function(colModel, colIndex, hidden){
47771 this.hideColumn(colIndex);
47773 this.unhideColumn(colIndex);
47777 hideColumn : function(colIndex){
47778 var cid = this.getColumnId(colIndex);
47779 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
47780 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
47782 this.updateHeaders();
47784 this.updateSplitters();
47788 unhideColumn : function(colIndex){
47789 var cid = this.getColumnId(colIndex);
47790 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
47791 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
47794 this.updateHeaders();
47796 this.updateSplitters();
47800 insertRows : function(dm, firstRow, lastRow, isUpdate){
47801 if(firstRow == 0 && lastRow == dm.getCount()-1){
47805 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
47807 var s = this.getScrollState();
47808 var markup = this.renderRows(firstRow, lastRow);
47809 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
47810 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
47811 this.restoreScroll(s);
47813 this.fireEvent("rowsinserted", this, firstRow, lastRow);
47814 this.syncRowHeights(firstRow, lastRow);
47815 this.stripeRows(firstRow);
47821 bufferRows : function(markup, target, index){
47822 var before = null, trows = target.rows, tbody = target.tBodies[0];
47823 if(index < trows.length){
47824 before = trows[index];
47826 var b = document.createElement("div");
47827 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
47828 var rows = b.firstChild.rows;
47829 for(var i = 0, len = rows.length; i < len; i++){
47831 tbody.insertBefore(rows[0], before);
47833 tbody.appendChild(rows[0]);
47840 deleteRows : function(dm, firstRow, lastRow){
47841 if(dm.getRowCount()<1){
47842 this.fireEvent("beforerefresh", this);
47843 this.mainBody.update("");
47844 this.lockedBody.update("");
47845 this.fireEvent("refresh", this);
47847 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
47848 var bt = this.getBodyTable();
47849 var tbody = bt.firstChild;
47850 var rows = bt.rows;
47851 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
47852 tbody.removeChild(rows[firstRow]);
47854 this.stripeRows(firstRow);
47855 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
47859 updateRows : function(dataSource, firstRow, lastRow){
47860 var s = this.getScrollState();
47862 this.restoreScroll(s);
47865 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
47869 this.updateHeaderSortState();
47872 getScrollState : function(){
47873 var sb = this.scroller.dom;
47874 return {left: sb.scrollLeft, top: sb.scrollTop};
47877 stripeRows : function(startRow){
47878 if(!this.grid.stripeRows || this.ds.getCount() < 1){
47881 startRow = startRow || 0;
47882 var rows = this.getBodyTable().rows;
47883 var lrows = this.getLockedTable().rows;
47884 var cls = ' x-grid-row-alt ';
47885 for(var i = startRow, len = rows.length; i < len; i++){
47886 var row = rows[i], lrow = lrows[i];
47887 var isAlt = ((i+1) % 2 == 0);
47888 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
47889 if(isAlt == hasAlt){
47893 row.className += " x-grid-row-alt";
47895 row.className = row.className.replace("x-grid-row-alt", "");
47898 lrow.className = row.className;
47903 restoreScroll : function(state){
47904 var sb = this.scroller.dom;
47905 sb.scrollLeft = state.left;
47906 sb.scrollTop = state.top;
47910 syncScroll : function(){
47911 var sb = this.scroller.dom;
47912 var sh = this.mainHd.dom;
47913 var bs = this.mainBody.dom;
47914 var lv = this.lockedBody.dom;
47915 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
47916 lv.scrollTop = bs.scrollTop = sb.scrollTop;
47919 handleScroll : function(e){
47921 var sb = this.scroller.dom;
47922 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
47926 handleWheel : function(e){
47927 var d = e.getWheelDelta();
47928 this.scroller.dom.scrollTop -= d*22;
47929 // set this here to prevent jumpy scrolling on large tables
47930 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
47934 renderRows : function(startRow, endRow){
47935 // pull in all the crap needed to render rows
47936 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
47937 var colCount = cm.getColumnCount();
47939 if(ds.getCount() < 1){
47943 // build a map for all the columns
47945 for(var i = 0; i < colCount; i++){
47946 var name = cm.getDataIndex(i);
47948 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
47949 renderer : cm.getRenderer(i),
47950 id : cm.getColumnId(i),
47951 locked : cm.isLocked(i)
47955 startRow = startRow || 0;
47956 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
47958 // records to render
47959 var rs = ds.getRange(startRow, endRow);
47961 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
47964 // As much as I hate to duplicate code, this was branched because FireFox really hates
47965 // [].join("") on strings. The performance difference was substantial enough to
47966 // branch this function
47967 doRender : Roo.isGecko ?
47968 function(cs, rs, ds, startRow, colCount, stripe){
47969 var ts = this.templates, ct = ts.cell, rt = ts.row;
47971 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47972 for(var j = 0, len = rs.length; j < len; j++){
47973 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
47974 for(var i = 0; i < colCount; i++){
47976 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47978 p.css = p.attr = "";
47979 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47980 if(p.value == undefined || p.value === "") p.value = " ";
47981 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47982 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47984 var markup = ct.apply(p);
47992 if(stripe && ((rowIndex+1) % 2 == 0)){
47993 alt[0] = "x-grid-row-alt";
47996 alt[1] = " x-grid-dirty-row";
47999 if(this.getRowClass){
48000 alt[2] = this.getRowClass(r, rowIndex);
48002 rp.alt = alt.join(" ");
48003 lbuf+= rt.apply(rp);
48005 buf+= rt.apply(rp);
48007 return [lbuf, buf];
48009 function(cs, rs, ds, startRow, colCount, stripe){
48010 var ts = this.templates, ct = ts.cell, rt = ts.row;
48012 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48013 for(var j = 0, len = rs.length; j < len; j++){
48014 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
48015 for(var i = 0; i < colCount; i++){
48017 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48019 p.css = p.attr = "";
48020 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48021 if(p.value == undefined || p.value === "") p.value = " ";
48022 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48023 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48025 var markup = ct.apply(p);
48027 cb[cb.length] = markup;
48029 lcb[lcb.length] = markup;
48033 if(stripe && ((rowIndex+1) % 2 == 0)){
48034 alt[0] = "x-grid-row-alt";
48037 alt[1] = " x-grid-dirty-row";
48040 if(this.getRowClass){
48041 alt[2] = this.getRowClass(r, rowIndex);
48043 rp.alt = alt.join(" ");
48044 rp.cells = lcb.join("");
48045 lbuf[lbuf.length] = rt.apply(rp);
48046 rp.cells = cb.join("");
48047 buf[buf.length] = rt.apply(rp);
48049 return [lbuf.join(""), buf.join("")];
48052 renderBody : function(){
48053 var markup = this.renderRows();
48054 var bt = this.templates.body;
48055 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48059 * Refreshes the grid
48060 * @param {Boolean} headersToo
48062 refresh : function(headersToo){
48063 this.fireEvent("beforerefresh", this);
48064 this.grid.stopEditing();
48065 var result = this.renderBody();
48066 this.lockedBody.update(result[0]);
48067 this.mainBody.update(result[1]);
48068 if(headersToo === true){
48069 this.updateHeaders();
48070 this.updateColumns();
48071 this.updateSplitters();
48072 this.updateHeaderSortState();
48074 this.syncRowHeights();
48076 this.fireEvent("refresh", this);
48079 handleColumnMove : function(cm, oldIndex, newIndex){
48080 this.indexMap = null;
48081 var s = this.getScrollState();
48082 this.refresh(true);
48083 this.restoreScroll(s);
48084 this.afterMove(newIndex);
48087 afterMove : function(colIndex){
48088 if(this.enableMoveAnim && Roo.enableFx){
48089 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48093 updateCell : function(dm, rowIndex, dataIndex){
48094 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48095 if(typeof colIndex == "undefined"){ // not present in grid
48098 var cm = this.grid.colModel;
48099 var cell = this.getCell(rowIndex, colIndex);
48100 var cellText = this.getCellText(rowIndex, colIndex);
48103 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48104 id : cm.getColumnId(colIndex),
48105 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48107 var renderer = cm.getRenderer(colIndex);
48108 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48109 if(typeof val == "undefined" || val === "") val = " ";
48110 cellText.innerHTML = val;
48111 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48112 this.syncRowHeights(rowIndex, rowIndex);
48115 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48117 if(this.grid.autoSizeHeaders){
48118 var h = this.getHeaderCellMeasure(colIndex);
48119 maxWidth = Math.max(maxWidth, h.scrollWidth);
48122 if(this.cm.isLocked(colIndex)){
48123 tb = this.getLockedTable();
48126 tb = this.getBodyTable();
48127 index = colIndex - this.cm.getLockedCount();
48130 var rows = tb.rows;
48131 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48132 for(var i = 0; i < stopIndex; i++){
48133 var cell = rows[i].childNodes[index].firstChild;
48134 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48137 return maxWidth + /*margin for error in IE*/ 5;
48140 * Autofit a column to its content.
48141 * @param {Number} colIndex
48142 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48144 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48145 if(this.cm.isHidden(colIndex)){
48146 return; // can't calc a hidden column
48149 var cid = this.cm.getColumnId(colIndex);
48150 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48151 if(this.grid.autoSizeHeaders){
48152 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48155 var newWidth = this.calcColumnWidth(colIndex);
48156 this.cm.setColumnWidth(colIndex,
48157 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48158 if(!suppressEvent){
48159 this.grid.fireEvent("columnresize", colIndex, newWidth);
48164 * Autofits all columns to their content and then expands to fit any extra space in the grid
48166 autoSizeColumns : function(){
48167 var cm = this.grid.colModel;
48168 var colCount = cm.getColumnCount();
48169 for(var i = 0; i < colCount; i++){
48170 this.autoSizeColumn(i, true, true);
48172 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48175 this.updateColumns();
48181 * Autofits all columns to the grid's width proportionate with their current size
48182 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48184 fitColumns : function(reserveScrollSpace){
48185 var cm = this.grid.colModel;
48186 var colCount = cm.getColumnCount();
48190 for (i = 0; i < colCount; i++){
48191 if(!cm.isHidden(i) && !cm.isFixed(i)){
48192 w = cm.getColumnWidth(i);
48198 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48199 if(reserveScrollSpace){
48202 var frac = (avail - cm.getTotalWidth())/width;
48203 while (cols.length){
48206 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48208 this.updateColumns();
48212 onRowSelect : function(rowIndex){
48213 var row = this.getRowComposite(rowIndex);
48214 row.addClass("x-grid-row-selected");
48217 onRowDeselect : function(rowIndex){
48218 var row = this.getRowComposite(rowIndex);
48219 row.removeClass("x-grid-row-selected");
48222 onCellSelect : function(row, col){
48223 var cell = this.getCell(row, col);
48225 Roo.fly(cell).addClass("x-grid-cell-selected");
48229 onCellDeselect : function(row, col){
48230 var cell = this.getCell(row, col);
48232 Roo.fly(cell).removeClass("x-grid-cell-selected");
48236 updateHeaderSortState : function(){
48237 var state = this.ds.getSortState();
48241 this.sortState = state;
48242 var sortColumn = this.cm.findColumnIndex(state.field);
48243 if(sortColumn != -1){
48244 var sortDir = state.direction;
48245 var sc = this.sortClasses;
48246 var hds = this.el.select(this.headerSelector).removeClass(sc);
48247 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48251 handleHeaderClick : function(g, index){
48252 if(this.headersDisabled){
48255 var dm = g.dataSource, cm = g.colModel;
48256 if(!cm.isSortable(index)){
48260 dm.sort(cm.getDataIndex(index));
48264 destroy : function(){
48266 this.colMenu.removeAll();
48267 Roo.menu.MenuMgr.unregister(this.colMenu);
48268 this.colMenu.getEl().remove();
48269 delete this.colMenu;
48272 this.hmenu.removeAll();
48273 Roo.menu.MenuMgr.unregister(this.hmenu);
48274 this.hmenu.getEl().remove();
48277 if(this.grid.enableColumnMove){
48278 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48280 for(var dd in dds){
48281 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48282 var elid = dds[dd].dragElId;
48284 Roo.get(elid).remove();
48285 } else if(dds[dd].config.isTarget){
48286 dds[dd].proxyTop.remove();
48287 dds[dd].proxyBottom.remove();
48290 if(Roo.dd.DDM.locationCache[dd]){
48291 delete Roo.dd.DDM.locationCache[dd];
48294 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48297 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48298 this.bind(null, null);
48299 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48302 handleLockChange : function(){
48303 this.refresh(true);
48306 onDenyColumnLock : function(){
48310 onDenyColumnHide : function(){
48314 handleHdMenuClick : function(item){
48315 var index = this.hdCtxIndex;
48316 var cm = this.cm, ds = this.ds;
48319 ds.sort(cm.getDataIndex(index), "ASC");
48322 ds.sort(cm.getDataIndex(index), "DESC");
48325 var lc = cm.getLockedCount();
48326 if(cm.getColumnCount(true) <= lc+1){
48327 this.onDenyColumnLock();
48331 cm.setLocked(index, true, true);
48332 cm.moveColumn(index, lc);
48333 this.grid.fireEvent("columnmove", index, lc);
48335 cm.setLocked(index, true);
48339 var lc = cm.getLockedCount();
48340 if((lc-1) != index){
48341 cm.setLocked(index, false, true);
48342 cm.moveColumn(index, lc-1);
48343 this.grid.fireEvent("columnmove", index, lc-1);
48345 cm.setLocked(index, false);
48349 index = cm.getIndexById(item.id.substr(4));
48351 if(item.checked && cm.getColumnCount(true) <= 1){
48352 this.onDenyColumnHide();
48355 cm.setHidden(index, item.checked);
48361 beforeColMenuShow : function(){
48362 var cm = this.cm, colCount = cm.getColumnCount();
48363 this.colMenu.removeAll();
48364 for(var i = 0; i < colCount; i++){
48365 this.colMenu.add(new Roo.menu.CheckItem({
48366 id: "col-"+cm.getColumnId(i),
48367 text: cm.getColumnHeader(i),
48368 checked: !cm.isHidden(i),
48374 handleHdCtx : function(g, index, e){
48376 var hd = this.getHeaderCell(index);
48377 this.hdCtxIndex = index;
48378 var ms = this.hmenu.items, cm = this.cm;
48379 ms.get("asc").setDisabled(!cm.isSortable(index));
48380 ms.get("desc").setDisabled(!cm.isSortable(index));
48381 if(this.grid.enableColLock !== false){
48382 ms.get("lock").setDisabled(cm.isLocked(index));
48383 ms.get("unlock").setDisabled(!cm.isLocked(index));
48385 this.hmenu.show(hd, "tl-bl");
48388 handleHdOver : function(e){
48389 var hd = this.findHeaderCell(e.getTarget());
48390 if(hd && !this.headersDisabled){
48391 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48392 this.fly(hd).addClass("x-grid-hd-over");
48397 handleHdOut : function(e){
48398 var hd = this.findHeaderCell(e.getTarget());
48400 this.fly(hd).removeClass("x-grid-hd-over");
48404 handleSplitDblClick : function(e, t){
48405 var i = this.getCellIndex(t);
48406 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48407 this.autoSizeColumn(i, true);
48412 render : function(){
48415 var colCount = cm.getColumnCount();
48417 if(this.grid.monitorWindowResize === true){
48418 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48420 var header = this.renderHeaders();
48421 var body = this.templates.body.apply({rows:""});
48422 var html = this.templates.master.apply({
48425 lockedHeader: header[0],
48429 //this.updateColumns();
48431 this.grid.getGridEl().dom.innerHTML = html;
48433 this.initElements();
48435 // a kludge to fix the random scolling effect in webkit
48436 this.el.on("scroll", function() {
48437 this.el.dom.scrollTop=0; // hopefully not recursive..
48440 this.scroller.on("scroll", this.handleScroll, this);
48441 this.lockedBody.on("mousewheel", this.handleWheel, this);
48442 this.mainBody.on("mousewheel", this.handleWheel, this);
48444 this.mainHd.on("mouseover", this.handleHdOver, this);
48445 this.mainHd.on("mouseout", this.handleHdOut, this);
48446 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48447 {delegate: "."+this.splitClass});
48449 this.lockedHd.on("mouseover", this.handleHdOver, this);
48450 this.lockedHd.on("mouseout", this.handleHdOut, this);
48451 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48452 {delegate: "."+this.splitClass});
48454 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48455 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48458 this.updateSplitters();
48460 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48461 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48462 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48465 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48466 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48468 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48469 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48471 if(this.grid.enableColLock !== false){
48472 this.hmenu.add('-',
48473 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48474 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48477 if(this.grid.enableColumnHide !== false){
48479 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48480 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48481 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48483 this.hmenu.add('-',
48484 {id:"columns", text: this.columnsText, menu: this.colMenu}
48487 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48489 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48492 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48493 this.dd = new Roo.grid.GridDragZone(this.grid, {
48494 ddGroup : this.grid.ddGroup || 'GridDD'
48499 for(var i = 0; i < colCount; i++){
48500 if(cm.isHidden(i)){
48501 this.hideColumn(i);
48503 if(cm.config[i].align){
48504 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48505 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48509 this.updateHeaderSortState();
48511 this.beforeInitialResize();
48514 // two part rendering gives faster view to the user
48515 this.renderPhase2.defer(1, this);
48518 renderPhase2 : function(){
48519 // render the rows now
48521 if(this.grid.autoSizeColumns){
48522 this.autoSizeColumns();
48526 beforeInitialResize : function(){
48530 onColumnSplitterMoved : function(i, w){
48531 this.userResized = true;
48532 var cm = this.grid.colModel;
48533 cm.setColumnWidth(i, w, true);
48534 var cid = cm.getColumnId(i);
48535 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48536 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48537 this.updateSplitters();
48539 this.grid.fireEvent("columnresize", i, w);
48542 syncRowHeights : function(startIndex, endIndex){
48543 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48544 startIndex = startIndex || 0;
48545 var mrows = this.getBodyTable().rows;
48546 var lrows = this.getLockedTable().rows;
48547 var len = mrows.length-1;
48548 endIndex = Math.min(endIndex || len, len);
48549 for(var i = startIndex; i <= endIndex; i++){
48550 var m = mrows[i], l = lrows[i];
48551 var h = Math.max(m.offsetHeight, l.offsetHeight);
48552 m.style.height = l.style.height = h + "px";
48557 layout : function(initialRender, is2ndPass){
48559 var auto = g.autoHeight;
48560 var scrollOffset = 16;
48561 var c = g.getGridEl(), cm = this.cm,
48562 expandCol = g.autoExpandColumn,
48564 //c.beginMeasure();
48566 if(!c.dom.offsetWidth){ // display:none?
48568 this.lockedWrap.show();
48569 this.mainWrap.show();
48574 var hasLock = this.cm.isLocked(0);
48576 var tbh = this.headerPanel.getHeight();
48577 var bbh = this.footerPanel.getHeight();
48580 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
48581 var newHeight = ch + c.getBorderWidth("tb");
48583 newHeight = Math.min(g.maxHeight, newHeight);
48585 c.setHeight(newHeight);
48589 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48592 var s = this.scroller;
48594 var csize = c.getSize(true);
48596 this.el.setSize(csize.width, csize.height);
48598 this.headerPanel.setWidth(csize.width);
48599 this.footerPanel.setWidth(csize.width);
48601 var hdHeight = this.mainHd.getHeight();
48602 var vw = csize.width;
48603 var vh = csize.height - (tbh + bbh);
48607 var bt = this.getBodyTable();
48608 var ltWidth = hasLock ?
48609 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
48611 var scrollHeight = bt.offsetHeight;
48612 var scrollWidth = ltWidth + bt.offsetWidth;
48613 var vscroll = false, hscroll = false;
48615 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
48617 var lw = this.lockedWrap, mw = this.mainWrap;
48618 var lb = this.lockedBody, mb = this.mainBody;
48620 setTimeout(function(){
48621 var t = s.dom.offsetTop;
48622 var w = s.dom.clientWidth,
48623 h = s.dom.clientHeight;
48626 lw.setSize(ltWidth, h);
48628 mw.setLeftTop(ltWidth, t);
48629 mw.setSize(w-ltWidth, h);
48631 lb.setHeight(h-hdHeight);
48632 mb.setHeight(h-hdHeight);
48634 if(is2ndPass !== true && !gv.userResized && expandCol){
48635 // high speed resize without full column calculation
48637 var ci = cm.getIndexById(expandCol);
48639 ci = cm.findColumnIndex(expandCol);
48641 ci = Math.max(0, ci); // make sure it's got at least the first col.
48642 var expandId = cm.getColumnId(ci);
48643 var tw = cm.getTotalWidth(false);
48644 var currentWidth = cm.getColumnWidth(ci);
48645 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
48646 if(currentWidth != cw){
48647 cm.setColumnWidth(ci, cw, true);
48648 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48649 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48650 gv.updateSplitters();
48651 gv.layout(false, true);
48663 onWindowResize : function(){
48664 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
48670 appendFooter : function(parentEl){
48674 sortAscText : "Sort Ascending",
48675 sortDescText : "Sort Descending",
48676 lockText : "Lock Column",
48677 unlockText : "Unlock Column",
48678 columnsText : "Columns"
48682 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
48683 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
48684 this.proxy.el.addClass('x-grid3-col-dd');
48687 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
48688 handleMouseDown : function(e){
48692 callHandleMouseDown : function(e){
48693 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
48698 * Ext JS Library 1.1.1
48699 * Copyright(c) 2006-2007, Ext JS, LLC.
48701 * Originally Released Under LGPL - original licence link has changed is not relivant.
48704 * <script type="text/javascript">
48708 // This is a support class used internally by the Grid components
48709 Roo.grid.SplitDragZone = function(grid, hd, hd2){
48711 this.view = grid.getView();
48712 this.proxy = this.view.resizeProxy;
48713 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
48714 "gridSplitters" + this.grid.getGridEl().id, {
48715 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
48717 this.setHandleElId(Roo.id(hd));
48718 this.setOuterHandleElId(Roo.id(hd2));
48719 this.scroll = false;
48721 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
48722 fly: Roo.Element.fly,
48724 b4StartDrag : function(x, y){
48725 this.view.headersDisabled = true;
48726 this.proxy.setHeight(this.view.mainWrap.getHeight());
48727 var w = this.cm.getColumnWidth(this.cellIndex);
48728 var minw = Math.max(w-this.grid.minColumnWidth, 0);
48729 this.resetConstraints();
48730 this.setXConstraint(minw, 1000);
48731 this.setYConstraint(0, 0);
48732 this.minX = x - minw;
48733 this.maxX = x + 1000;
48735 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
48739 handleMouseDown : function(e){
48740 ev = Roo.EventObject.setEvent(e);
48741 var t = this.fly(ev.getTarget());
48742 if(t.hasClass("x-grid-split")){
48743 this.cellIndex = this.view.getCellIndex(t.dom);
48744 this.split = t.dom;
48745 this.cm = this.grid.colModel;
48746 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
48747 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
48752 endDrag : function(e){
48753 this.view.headersDisabled = false;
48754 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
48755 var diff = endX - this.startPos;
48756 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
48759 autoOffset : function(){
48760 this.setDelta(0,0);
48764 * Ext JS Library 1.1.1
48765 * Copyright(c) 2006-2007, Ext JS, LLC.
48767 * Originally Released Under LGPL - original licence link has changed is not relivant.
48770 * <script type="text/javascript">
48774 // This is a support class used internally by the Grid components
48775 Roo.grid.GridDragZone = function(grid, config){
48776 this.view = grid.getView();
48777 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
48778 if(this.view.lockedBody){
48779 this.setHandleElId(Roo.id(this.view.mainBody.dom));
48780 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
48782 this.scroll = false;
48784 this.ddel = document.createElement('div');
48785 this.ddel.className = 'x-grid-dd-wrap';
48788 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
48789 ddGroup : "GridDD",
48791 getDragData : function(e){
48792 var t = Roo.lib.Event.getTarget(e);
48793 var rowIndex = this.view.findRowIndex(t);
48794 if(rowIndex !== false){
48795 var sm = this.grid.selModel;
48796 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
48797 // sm.mouseDown(e, t);
48799 if (e.hasModifier()){
48800 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
48802 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
48807 onInitDrag : function(e){
48808 var data = this.dragData;
48809 this.ddel.innerHTML = this.grid.getDragDropText();
48810 this.proxy.update(this.ddel);
48811 // fire start drag?
48814 afterRepair : function(){
48815 this.dragging = false;
48818 getRepairXY : function(e, data){
48822 onEndDrag : function(data, e){
48826 onValidDrop : function(dd, e, id){
48831 beforeInvalidDrop : function(e, id){
48836 * Ext JS Library 1.1.1
48837 * Copyright(c) 2006-2007, Ext JS, LLC.
48839 * Originally Released Under LGPL - original licence link has changed is not relivant.
48842 * <script type="text/javascript">
48847 * @class Roo.grid.ColumnModel
48848 * @extends Roo.util.Observable
48849 * This is the default implementation of a ColumnModel used by the Grid. It defines
48850 * the columns in the grid.
48853 var colModel = new Roo.grid.ColumnModel([
48854 {header: "Ticker", width: 60, sortable: true, locked: true},
48855 {header: "Company Name", width: 150, sortable: true},
48856 {header: "Market Cap.", width: 100, sortable: true},
48857 {header: "$ Sales", width: 100, sortable: true, renderer: money},
48858 {header: "Employees", width: 100, sortable: true, resizable: false}
48863 * The config options listed for this class are options which may appear in each
48864 * individual column definition.
48865 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
48867 * @param {Object} config An Array of column config objects. See this class's
48868 * config objects for details.
48870 Roo.grid.ColumnModel = function(config){
48872 * The config passed into the constructor
48874 this.config = config;
48877 // if no id, create one
48878 // if the column does not have a dataIndex mapping,
48879 // map it to the order it is in the config
48880 for(var i = 0, len = config.length; i < len; i++){
48882 if(typeof c.dataIndex == "undefined"){
48885 if(typeof c.renderer == "string"){
48886 c.renderer = Roo.util.Format[c.renderer];
48888 if(typeof c.id == "undefined"){
48891 if(c.editor && c.editor.xtype){
48892 c.editor = Roo.factory(c.editor, Roo.grid);
48894 if(c.editor && c.editor.isFormField){
48895 c.editor = new Roo.grid.GridEditor(c.editor);
48897 this.lookup[c.id] = c;
48901 * The width of columns which have no width specified (defaults to 100)
48904 this.defaultWidth = 100;
48907 * Default sortable of columns which have no sortable specified (defaults to false)
48910 this.defaultSortable = false;
48914 * @event widthchange
48915 * Fires when the width of a column changes.
48916 * @param {ColumnModel} this
48917 * @param {Number} columnIndex The column index
48918 * @param {Number} newWidth The new width
48920 "widthchange": true,
48922 * @event headerchange
48923 * Fires when the text of a header changes.
48924 * @param {ColumnModel} this
48925 * @param {Number} columnIndex The column index
48926 * @param {Number} newText The new header text
48928 "headerchange": true,
48930 * @event hiddenchange
48931 * Fires when a column is hidden or "unhidden".
48932 * @param {ColumnModel} this
48933 * @param {Number} columnIndex The column index
48934 * @param {Boolean} hidden true if hidden, false otherwise
48936 "hiddenchange": true,
48938 * @event columnmoved
48939 * Fires when a column is moved.
48940 * @param {ColumnModel} this
48941 * @param {Number} oldIndex
48942 * @param {Number} newIndex
48944 "columnmoved" : true,
48946 * @event columlockchange
48947 * Fires when a column's locked state is changed
48948 * @param {ColumnModel} this
48949 * @param {Number} colIndex
48950 * @param {Boolean} locked true if locked
48952 "columnlockchange" : true
48954 Roo.grid.ColumnModel.superclass.constructor.call(this);
48956 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
48958 * @cfg {String} header The header text to display in the Grid view.
48961 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
48962 * {@link Roo.data.Record} definition from which to draw the column's value. If not
48963 * specified, the column's index is used as an index into the Record's data Array.
48966 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
48967 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
48970 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
48971 * Defaults to the value of the {@link #defaultSortable} property.
48972 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
48975 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
48978 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
48981 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
48984 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
48987 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
48988 * given the cell's data value. See {@link #setRenderer}. If not specified, the
48989 * default renderer uses the raw data value.
48992 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
48995 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
48999 * Returns the id of the column at the specified index.
49000 * @param {Number} index The column index
49001 * @return {String} the id
49003 getColumnId : function(index){
49004 return this.config[index].id;
49008 * Returns the column for a specified id.
49009 * @param {String} id The column id
49010 * @return {Object} the column
49012 getColumnById : function(id){
49013 return this.lookup[id];
49018 * Returns the column for a specified dataIndex.
49019 * @param {String} dataIndex The column dataIndex
49020 * @return {Object|Boolean} the column or false if not found
49022 getColumnByDataIndex: function(dataIndex){
49023 var index = this.findColumnIndex(dataIndex);
49024 return index > -1 ? this.config[index] : false;
49028 * Returns the index for a specified column id.
49029 * @param {String} id The column id
49030 * @return {Number} the index, or -1 if not found
49032 getIndexById : function(id){
49033 for(var i = 0, len = this.config.length; i < len; i++){
49034 if(this.config[i].id == id){
49042 * Returns the index for a specified column dataIndex.
49043 * @param {String} dataIndex The column dataIndex
49044 * @return {Number} the index, or -1 if not found
49047 findColumnIndex : function(dataIndex){
49048 for(var i = 0, len = this.config.length; i < len; i++){
49049 if(this.config[i].dataIndex == dataIndex){
49057 moveColumn : function(oldIndex, newIndex){
49058 var c = this.config[oldIndex];
49059 this.config.splice(oldIndex, 1);
49060 this.config.splice(newIndex, 0, c);
49061 this.dataMap = null;
49062 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49065 isLocked : function(colIndex){
49066 return this.config[colIndex].locked === true;
49069 setLocked : function(colIndex, value, suppressEvent){
49070 if(this.isLocked(colIndex) == value){
49073 this.config[colIndex].locked = value;
49074 if(!suppressEvent){
49075 this.fireEvent("columnlockchange", this, colIndex, value);
49079 getTotalLockedWidth : function(){
49080 var totalWidth = 0;
49081 for(var i = 0; i < this.config.length; i++){
49082 if(this.isLocked(i) && !this.isHidden(i)){
49083 this.totalWidth += this.getColumnWidth(i);
49089 getLockedCount : function(){
49090 for(var i = 0, len = this.config.length; i < len; i++){
49091 if(!this.isLocked(i)){
49098 * Returns the number of columns.
49101 getColumnCount : function(visibleOnly){
49102 if(visibleOnly === true){
49104 for(var i = 0, len = this.config.length; i < len; i++){
49105 if(!this.isHidden(i)){
49111 return this.config.length;
49115 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49116 * @param {Function} fn
49117 * @param {Object} scope (optional)
49118 * @return {Array} result
49120 getColumnsBy : function(fn, scope){
49122 for(var i = 0, len = this.config.length; i < len; i++){
49123 var c = this.config[i];
49124 if(fn.call(scope||this, c, i) === true){
49132 * Returns true if the specified column is sortable.
49133 * @param {Number} col The column index
49134 * @return {Boolean}
49136 isSortable : function(col){
49137 if(typeof this.config[col].sortable == "undefined"){
49138 return this.defaultSortable;
49140 return this.config[col].sortable;
49144 * Returns the rendering (formatting) function defined for the column.
49145 * @param {Number} col The column index.
49146 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49148 getRenderer : function(col){
49149 if(!this.config[col].renderer){
49150 return Roo.grid.ColumnModel.defaultRenderer;
49152 return this.config[col].renderer;
49156 * Sets the rendering (formatting) function for a column.
49157 * @param {Number} col The column index
49158 * @param {Function} fn The function to use to process the cell's raw data
49159 * to return HTML markup for the grid view. The render function is called with
49160 * the following parameters:<ul>
49161 * <li>Data value.</li>
49162 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49163 * <li>css A CSS style string to apply to the table cell.</li>
49164 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49165 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49166 * <li>Row index</li>
49167 * <li>Column index</li>
49168 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49170 setRenderer : function(col, fn){
49171 this.config[col].renderer = fn;
49175 * Returns the width for the specified column.
49176 * @param {Number} col The column index
49179 getColumnWidth : function(col){
49180 return this.config[col].width || this.defaultWidth;
49184 * Sets the width for a column.
49185 * @param {Number} col The column index
49186 * @param {Number} width The new width
49188 setColumnWidth : function(col, width, suppressEvent){
49189 this.config[col].width = width;
49190 this.totalWidth = null;
49191 if(!suppressEvent){
49192 this.fireEvent("widthchange", this, col, width);
49197 * Returns the total width of all columns.
49198 * @param {Boolean} includeHidden True to include hidden column widths
49201 getTotalWidth : function(includeHidden){
49202 if(!this.totalWidth){
49203 this.totalWidth = 0;
49204 for(var i = 0, len = this.config.length; i < len; i++){
49205 if(includeHidden || !this.isHidden(i)){
49206 this.totalWidth += this.getColumnWidth(i);
49210 return this.totalWidth;
49214 * Returns the header for the specified column.
49215 * @param {Number} col The column index
49218 getColumnHeader : function(col){
49219 return this.config[col].header;
49223 * Sets the header for a column.
49224 * @param {Number} col The column index
49225 * @param {String} header The new header
49227 setColumnHeader : function(col, header){
49228 this.config[col].header = header;
49229 this.fireEvent("headerchange", this, col, header);
49233 * Returns the tooltip for the specified column.
49234 * @param {Number} col The column index
49237 getColumnTooltip : function(col){
49238 return this.config[col].tooltip;
49241 * Sets the tooltip for a column.
49242 * @param {Number} col The column index
49243 * @param {String} tooltip The new tooltip
49245 setColumnTooltip : function(col, tooltip){
49246 this.config[col].tooltip = tooltip;
49250 * Returns the dataIndex for the specified column.
49251 * @param {Number} col The column index
49254 getDataIndex : function(col){
49255 return this.config[col].dataIndex;
49259 * Sets the dataIndex for a column.
49260 * @param {Number} col The column index
49261 * @param {Number} dataIndex The new dataIndex
49263 setDataIndex : function(col, dataIndex){
49264 this.config[col].dataIndex = dataIndex;
49270 * Returns true if the cell is editable.
49271 * @param {Number} colIndex The column index
49272 * @param {Number} rowIndex The row index
49273 * @return {Boolean}
49275 isCellEditable : function(colIndex, rowIndex){
49276 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49280 * Returns the editor defined for the cell/column.
49281 * return false or null to disable editing.
49282 * @param {Number} colIndex The column index
49283 * @param {Number} rowIndex The row index
49286 getCellEditor : function(colIndex, rowIndex){
49287 return this.config[colIndex].editor;
49291 * Sets if a column is editable.
49292 * @param {Number} col The column index
49293 * @param {Boolean} editable True if the column is editable
49295 setEditable : function(col, editable){
49296 this.config[col].editable = editable;
49301 * Returns true if the column is hidden.
49302 * @param {Number} colIndex The column index
49303 * @return {Boolean}
49305 isHidden : function(colIndex){
49306 return this.config[colIndex].hidden;
49311 * Returns true if the column width cannot be changed
49313 isFixed : function(colIndex){
49314 return this.config[colIndex].fixed;
49318 * Returns true if the column can be resized
49319 * @return {Boolean}
49321 isResizable : function(colIndex){
49322 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49325 * Sets if a column is hidden.
49326 * @param {Number} colIndex The column index
49327 * @param {Boolean} hidden True if the column is hidden
49329 setHidden : function(colIndex, hidden){
49330 this.config[colIndex].hidden = hidden;
49331 this.totalWidth = null;
49332 this.fireEvent("hiddenchange", this, colIndex, hidden);
49336 * Sets the editor for a column.
49337 * @param {Number} col The column index
49338 * @param {Object} editor The editor object
49340 setEditor : function(col, editor){
49341 this.config[col].editor = editor;
49345 Roo.grid.ColumnModel.defaultRenderer = function(value){
49346 if(typeof value == "string" && value.length < 1){
49352 // Alias for backwards compatibility
49353 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49356 * Ext JS Library 1.1.1
49357 * Copyright(c) 2006-2007, Ext JS, LLC.
49359 * Originally Released Under LGPL - original licence link has changed is not relivant.
49362 * <script type="text/javascript">
49366 * @class Roo.grid.AbstractSelectionModel
49367 * @extends Roo.util.Observable
49368 * Abstract base class for grid SelectionModels. It provides the interface that should be
49369 * implemented by descendant classes. This class should not be directly instantiated.
49372 Roo.grid.AbstractSelectionModel = function(){
49373 this.locked = false;
49374 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49377 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49378 /** @ignore Called by the grid automatically. Do not call directly. */
49379 init : function(grid){
49385 * Locks the selections.
49388 this.locked = true;
49392 * Unlocks the selections.
49394 unlock : function(){
49395 this.locked = false;
49399 * Returns true if the selections are locked.
49400 * @return {Boolean}
49402 isLocked : function(){
49403 return this.locked;
49407 * Ext JS Library 1.1.1
49408 * Copyright(c) 2006-2007, Ext JS, LLC.
49410 * Originally Released Under LGPL - original licence link has changed is not relivant.
49413 * <script type="text/javascript">
49416 * @extends Roo.grid.AbstractSelectionModel
49417 * @class Roo.grid.RowSelectionModel
49418 * The default SelectionModel used by {@link Roo.grid.Grid}.
49419 * It supports multiple selections and keyboard selection/navigation.
49421 * @param {Object} config
49423 Roo.grid.RowSelectionModel = function(config){
49424 Roo.apply(this, config);
49425 this.selections = new Roo.util.MixedCollection(false, function(o){
49430 this.lastActive = false;
49434 * @event selectionchange
49435 * Fires when the selection changes
49436 * @param {SelectionModel} this
49438 "selectionchange" : true,
49440 * @event afterselectionchange
49441 * Fires after the selection changes (eg. by key press or clicking)
49442 * @param {SelectionModel} this
49444 "afterselectionchange" : true,
49446 * @event beforerowselect
49447 * Fires when a row is selected being selected, return false to cancel.
49448 * @param {SelectionModel} this
49449 * @param {Number} rowIndex The selected index
49450 * @param {Boolean} keepExisting False if other selections will be cleared
49452 "beforerowselect" : true,
49455 * Fires when a row is selected.
49456 * @param {SelectionModel} this
49457 * @param {Number} rowIndex The selected index
49458 * @param {Roo.data.Record} r The record
49460 "rowselect" : true,
49462 * @event rowdeselect
49463 * Fires when a row is deselected.
49464 * @param {SelectionModel} this
49465 * @param {Number} rowIndex The selected index
49467 "rowdeselect" : true
49469 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49470 this.locked = false;
49473 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49475 * @cfg {Boolean} singleSelect
49476 * True to allow selection of only one row at a time (defaults to false)
49478 singleSelect : false,
49481 initEvents : function(){
49483 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49484 this.grid.on("mousedown", this.handleMouseDown, this);
49485 }else{ // allow click to work like normal
49486 this.grid.on("rowclick", this.handleDragableRowClick, this);
49489 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49490 "up" : function(e){
49492 this.selectPrevious(e.shiftKey);
49493 }else if(this.last !== false && this.lastActive !== false){
49494 var last = this.last;
49495 this.selectRange(this.last, this.lastActive-1);
49496 this.grid.getView().focusRow(this.lastActive);
49497 if(last !== false){
49501 this.selectFirstRow();
49503 this.fireEvent("afterselectionchange", this);
49505 "down" : function(e){
49507 this.selectNext(e.shiftKey);
49508 }else if(this.last !== false && this.lastActive !== false){
49509 var last = this.last;
49510 this.selectRange(this.last, this.lastActive+1);
49511 this.grid.getView().focusRow(this.lastActive);
49512 if(last !== false){
49516 this.selectFirstRow();
49518 this.fireEvent("afterselectionchange", this);
49523 var view = this.grid.view;
49524 view.on("refresh", this.onRefresh, this);
49525 view.on("rowupdated", this.onRowUpdated, this);
49526 view.on("rowremoved", this.onRemove, this);
49530 onRefresh : function(){
49531 var ds = this.grid.dataSource, i, v = this.grid.view;
49532 var s = this.selections;
49533 s.each(function(r){
49534 if((i = ds.indexOfId(r.id)) != -1){
49543 onRemove : function(v, index, r){
49544 this.selections.remove(r);
49548 onRowUpdated : function(v, index, r){
49549 if(this.isSelected(r)){
49550 v.onRowSelect(index);
49556 * @param {Array} records The records to select
49557 * @param {Boolean} keepExisting (optional) True to keep existing selections
49559 selectRecords : function(records, keepExisting){
49561 this.clearSelections();
49563 var ds = this.grid.dataSource;
49564 for(var i = 0, len = records.length; i < len; i++){
49565 this.selectRow(ds.indexOf(records[i]), true);
49570 * Gets the number of selected rows.
49573 getCount : function(){
49574 return this.selections.length;
49578 * Selects the first row in the grid.
49580 selectFirstRow : function(){
49585 * Select the last row.
49586 * @param {Boolean} keepExisting (optional) True to keep existing selections
49588 selectLastRow : function(keepExisting){
49589 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
49593 * Selects the row immediately following the last selected row.
49594 * @param {Boolean} keepExisting (optional) True to keep existing selections
49596 selectNext : function(keepExisting){
49597 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49598 this.selectRow(this.last+1, keepExisting);
49599 this.grid.getView().focusRow(this.last);
49604 * Selects the row that precedes the last selected row.
49605 * @param {Boolean} keepExisting (optional) True to keep existing selections
49607 selectPrevious : function(keepExisting){
49609 this.selectRow(this.last-1, keepExisting);
49610 this.grid.getView().focusRow(this.last);
49615 * Returns the selected records
49616 * @return {Array} Array of selected records
49618 getSelections : function(){
49619 return [].concat(this.selections.items);
49623 * Returns the first selected record.
49626 getSelected : function(){
49627 return this.selections.itemAt(0);
49632 * Clears all selections.
49634 clearSelections : function(fast){
49635 if(this.locked) return;
49637 var ds = this.grid.dataSource;
49638 var s = this.selections;
49639 s.each(function(r){
49640 this.deselectRow(ds.indexOfId(r.id));
49644 this.selections.clear();
49651 * Selects all rows.
49653 selectAll : function(){
49654 if(this.locked) return;
49655 this.selections.clear();
49656 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
49657 this.selectRow(i, true);
49662 * Returns True if there is a selection.
49663 * @return {Boolean}
49665 hasSelection : function(){
49666 return this.selections.length > 0;
49670 * Returns True if the specified row is selected.
49671 * @param {Number/Record} record The record or index of the record to check
49672 * @return {Boolean}
49674 isSelected : function(index){
49675 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
49676 return (r && this.selections.key(r.id) ? true : false);
49680 * Returns True if the specified record id is selected.
49681 * @param {String} id The id of record to check
49682 * @return {Boolean}
49684 isIdSelected : function(id){
49685 return (this.selections.key(id) ? true : false);
49689 handleMouseDown : function(e, t){
49690 var view = this.grid.getView(), rowIndex;
49691 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
49694 if(e.shiftKey && this.last !== false){
49695 var last = this.last;
49696 this.selectRange(last, rowIndex, e.ctrlKey);
49697 this.last = last; // reset the last
49698 view.focusRow(rowIndex);
49700 var isSelected = this.isSelected(rowIndex);
49701 if(e.button !== 0 && isSelected){
49702 view.focusRow(rowIndex);
49703 }else if(e.ctrlKey && isSelected){
49704 this.deselectRow(rowIndex);
49705 }else if(!isSelected){
49706 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
49707 view.focusRow(rowIndex);
49710 this.fireEvent("afterselectionchange", this);
49713 handleDragableRowClick : function(grid, rowIndex, e)
49715 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
49716 this.selectRow(rowIndex, false);
49717 grid.view.focusRow(rowIndex);
49718 this.fireEvent("afterselectionchange", this);
49723 * Selects multiple rows.
49724 * @param {Array} rows Array of the indexes of the row to select
49725 * @param {Boolean} keepExisting (optional) True to keep existing selections
49727 selectRows : function(rows, keepExisting){
49729 this.clearSelections();
49731 for(var i = 0, len = rows.length; i < len; i++){
49732 this.selectRow(rows[i], true);
49737 * Selects a range of rows. All rows in between startRow and endRow are also selected.
49738 * @param {Number} startRow The index of the first row in the range
49739 * @param {Number} endRow The index of the last row in the range
49740 * @param {Boolean} keepExisting (optional) True to retain existing selections
49742 selectRange : function(startRow, endRow, keepExisting){
49743 if(this.locked) return;
49745 this.clearSelections();
49747 if(startRow <= endRow){
49748 for(var i = startRow; i <= endRow; i++){
49749 this.selectRow(i, true);
49752 for(var i = startRow; i >= endRow; i--){
49753 this.selectRow(i, true);
49759 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
49760 * @param {Number} startRow The index of the first row in the range
49761 * @param {Number} endRow The index of the last row in the range
49763 deselectRange : function(startRow, endRow, preventViewNotify){
49764 if(this.locked) return;
49765 for(var i = startRow; i <= endRow; i++){
49766 this.deselectRow(i, preventViewNotify);
49772 * @param {Number} row The index of the row to select
49773 * @param {Boolean} keepExisting (optional) True to keep existing selections
49775 selectRow : function(index, keepExisting, preventViewNotify){
49776 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
49777 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
49778 if(!keepExisting || this.singleSelect){
49779 this.clearSelections();
49781 var r = this.grid.dataSource.getAt(index);
49782 this.selections.add(r);
49783 this.last = this.lastActive = index;
49784 if(!preventViewNotify){
49785 this.grid.getView().onRowSelect(index);
49787 this.fireEvent("rowselect", this, index, r);
49788 this.fireEvent("selectionchange", this);
49794 * @param {Number} row The index of the row to deselect
49796 deselectRow : function(index, preventViewNotify){
49797 if(this.locked) return;
49798 if(this.last == index){
49801 if(this.lastActive == index){
49802 this.lastActive = false;
49804 var r = this.grid.dataSource.getAt(index);
49805 this.selections.remove(r);
49806 if(!preventViewNotify){
49807 this.grid.getView().onRowDeselect(index);
49809 this.fireEvent("rowdeselect", this, index);
49810 this.fireEvent("selectionchange", this);
49814 restoreLast : function(){
49816 this.last = this._last;
49821 acceptsNav : function(row, col, cm){
49822 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49826 onEditorKey : function(field, e){
49827 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49832 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49834 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49836 }else if(k == e.ENTER && !e.ctrlKey){
49840 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
49842 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
49844 }else if(k == e.ESC){
49848 g.startEditing(newCell[0], newCell[1]);
49853 * Ext JS Library 1.1.1
49854 * Copyright(c) 2006-2007, Ext JS, LLC.
49856 * Originally Released Under LGPL - original licence link has changed is not relivant.
49859 * <script type="text/javascript">
49862 * @class Roo.grid.CellSelectionModel
49863 * @extends Roo.grid.AbstractSelectionModel
49864 * This class provides the basic implementation for cell selection in a grid.
49866 * @param {Object} config The object containing the configuration of this model.
49868 Roo.grid.CellSelectionModel = function(config){
49869 Roo.apply(this, config);
49871 this.selection = null;
49875 * @event beforerowselect
49876 * Fires before a cell is selected.
49877 * @param {SelectionModel} this
49878 * @param {Number} rowIndex The selected row index
49879 * @param {Number} colIndex The selected cell index
49881 "beforecellselect" : true,
49883 * @event cellselect
49884 * Fires when a cell is selected.
49885 * @param {SelectionModel} this
49886 * @param {Number} rowIndex The selected row index
49887 * @param {Number} colIndex The selected cell index
49889 "cellselect" : true,
49891 * @event selectionchange
49892 * Fires when the active selection changes.
49893 * @param {SelectionModel} this
49894 * @param {Object} selection null for no selection or an object (o) with two properties
49896 <li>o.record: the record object for the row the selection is in</li>
49897 <li>o.cell: An array of [rowIndex, columnIndex]</li>
49900 "selectionchange" : true
49902 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
49905 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
49908 initEvents : function(){
49909 this.grid.on("mousedown", this.handleMouseDown, this);
49910 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
49911 var view = this.grid.view;
49912 view.on("refresh", this.onViewChange, this);
49913 view.on("rowupdated", this.onRowUpdated, this);
49914 view.on("beforerowremoved", this.clearSelections, this);
49915 view.on("beforerowsinserted", this.clearSelections, this);
49916 if(this.grid.isEditor){
49917 this.grid.on("beforeedit", this.beforeEdit, this);
49922 beforeEdit : function(e){
49923 this.select(e.row, e.column, false, true, e.record);
49927 onRowUpdated : function(v, index, r){
49928 if(this.selection && this.selection.record == r){
49929 v.onCellSelect(index, this.selection.cell[1]);
49934 onViewChange : function(){
49935 this.clearSelections(true);
49939 * Returns the currently selected cell,.
49940 * @return {Array} The selected cell (row, column) or null if none selected.
49942 getSelectedCell : function(){
49943 return this.selection ? this.selection.cell : null;
49947 * Clears all selections.
49948 * @param {Boolean} true to prevent the gridview from being notified about the change.
49950 clearSelections : function(preventNotify){
49951 var s = this.selection;
49953 if(preventNotify !== true){
49954 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
49956 this.selection = null;
49957 this.fireEvent("selectionchange", this, null);
49962 * Returns true if there is a selection.
49963 * @return {Boolean}
49965 hasSelection : function(){
49966 return this.selection ? true : false;
49970 handleMouseDown : function(e, t){
49971 var v = this.grid.getView();
49972 if(this.isLocked()){
49975 var row = v.findRowIndex(t);
49976 var cell = v.findCellIndex(t);
49977 if(row !== false && cell !== false){
49978 this.select(row, cell);
49984 * @param {Number} rowIndex
49985 * @param {Number} collIndex
49987 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
49988 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
49989 this.clearSelections();
49990 r = r || this.grid.dataSource.getAt(rowIndex);
49993 cell : [rowIndex, colIndex]
49995 if(!preventViewNotify){
49996 var v = this.grid.getView();
49997 v.onCellSelect(rowIndex, colIndex);
49998 if(preventFocus !== true){
49999 v.focusCell(rowIndex, colIndex);
50002 this.fireEvent("cellselect", this, rowIndex, colIndex);
50003 this.fireEvent("selectionchange", this, this.selection);
50008 isSelectable : function(rowIndex, colIndex, cm){
50009 return !cm.isHidden(colIndex);
50013 handleKeyDown : function(e){
50014 Roo.log('Cell Sel Model handleKeyDown');
50015 if(!e.isNavKeyPress()){
50018 var g = this.grid, s = this.selection;
50021 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
50023 this.select(cell[0], cell[1]);
50028 var walk = function(row, col, step){
50029 return g.walkCells(row, col, step, sm.isSelectable, sm);
50031 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
50036 // handled by onEditorKey
50037 if (g.isEditor && g.editing) {
50041 newCell = walk(r, c-1, -1);
50043 newCell = walk(r, c+1, 1);
50047 newCell = walk(r+1, c, 1);
50050 newCell = walk(r-1, c, -1);
50053 newCell = walk(r, c+1, 1);
50056 newCell = walk(r, c-1, -1);
50059 if(g.isEditor && !g.editing){
50060 g.startEditing(r, c);
50067 this.select(newCell[0], newCell[1]);
50072 acceptsNav : function(row, col, cm){
50073 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50076 onEditorKey : function(field, e){
50078 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50079 ///Roo.log('onEditorKey' + k);
50083 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50085 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50088 }else if(k == e.ENTER && !e.ctrlKey){
50091 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50092 }else if(k == e.ESC){
50098 //Roo.log('next cell after edit');
50099 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50104 * Ext JS Library 1.1.1
50105 * Copyright(c) 2006-2007, Ext JS, LLC.
50107 * Originally Released Under LGPL - original licence link has changed is not relivant.
50110 * <script type="text/javascript">
50114 * @class Roo.grid.EditorGrid
50115 * @extends Roo.grid.Grid
50116 * Class for creating and editable grid.
50117 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50118 * The container MUST have some type of size defined for the grid to fill. The container will be
50119 * automatically set to position relative if it isn't already.
50120 * @param {Object} dataSource The data model to bind to
50121 * @param {Object} colModel The column model with info about this grid's columns
50123 Roo.grid.EditorGrid = function(container, config){
50124 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50125 this.getGridEl().addClass("xedit-grid");
50127 if(!this.selModel){
50128 this.selModel = new Roo.grid.CellSelectionModel();
50131 this.activeEditor = null;
50135 * @event beforeedit
50136 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50137 * <ul style="padding:5px;padding-left:16px;">
50138 * <li>grid - This grid</li>
50139 * <li>record - The record being edited</li>
50140 * <li>field - The field name being edited</li>
50141 * <li>value - The value for the field being edited.</li>
50142 * <li>row - The grid row index</li>
50143 * <li>column - The grid column index</li>
50144 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50146 * @param {Object} e An edit event (see above for description)
50148 "beforeedit" : true,
50151 * Fires after a cell is edited. <br />
50152 * <ul style="padding:5px;padding-left:16px;">
50153 * <li>grid - This grid</li>
50154 * <li>record - The record being edited</li>
50155 * <li>field - The field name being edited</li>
50156 * <li>value - The value being set</li>
50157 * <li>originalValue - The original value for the field, before the edit.</li>
50158 * <li>row - The grid row index</li>
50159 * <li>column - The grid column index</li>
50161 * @param {Object} e An edit event (see above for description)
50163 "afteredit" : true,
50165 * @event validateedit
50166 * Fires after a cell is edited, but before the value is set in the record.
50167 * You can use this to modify the value being set in the field, Return false
50168 * to cancel the change. The edit event object has the following properties <br />
50169 * <ul style="padding:5px;padding-left:16px;">
50170 * <li>editor - This editor</li>
50171 * <li>grid - This grid</li>
50172 * <li>record - The record being edited</li>
50173 * <li>field - The field name being edited</li>
50174 * <li>value - The value being set</li>
50175 * <li>originalValue - The original value for the field, before the edit.</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 "validateedit" : true
50184 this.on("bodyscroll", this.stopEditing, this);
50185 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50188 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50190 * @cfg {Number} clicksToEdit
50191 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50198 trackMouseOver: false, // causes very odd FF errors
50200 onCellDblClick : function(g, row, col){
50201 this.startEditing(row, col);
50204 onEditComplete : function(ed, value, startValue){
50205 this.editing = false;
50206 this.activeEditor = null;
50207 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50209 var field = this.colModel.getDataIndex(ed.col);
50214 originalValue: startValue,
50221 if(String(value) !== String(startValue)){
50223 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50224 r.set(field, e.value);
50225 // if we are dealing with a combo box..
50226 // then we also set the 'name' colum to be the displayField
50227 if (ed.field.displayField && ed.field.name) {
50228 r.set(ed.field.name, ed.field.el.dom.value);
50231 delete e.cancel; //?? why!!!
50232 this.fireEvent("afteredit", e);
50235 this.fireEvent("afteredit", e); // always fire it!
50237 this.view.focusCell(ed.row, ed.col);
50241 * Starts editing the specified for the specified row/column
50242 * @param {Number} rowIndex
50243 * @param {Number} colIndex
50245 startEditing : function(row, col){
50246 this.stopEditing();
50247 if(this.colModel.isCellEditable(col, row)){
50248 this.view.ensureVisible(row, col, true);
50249 var r = this.dataSource.getAt(row);
50250 var field = this.colModel.getDataIndex(col);
50255 value: r.data[field],
50260 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50261 this.editing = true;
50262 var ed = this.colModel.getCellEditor(col, row);
50268 ed.render(ed.parentEl || document.body);
50271 (function(){ // complex but required for focus issues in safari, ie and opera
50275 ed.on("complete", this.onEditComplete, this, {single: true});
50276 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50277 this.activeEditor = ed;
50278 var v = r.data[field];
50279 ed.startEdit(this.view.getCell(row, col), v);
50280 // combo's with 'displayField and name set
50281 if (ed.field.displayField && ed.field.name) {
50282 ed.field.el.dom.value = r.data[ed.field.name];
50286 }).defer(50, this);
50292 * Stops any active editing
50294 stopEditing : function(){
50295 if(this.activeEditor){
50296 this.activeEditor.completeEdit();
50298 this.activeEditor = null;
50302 * Ext JS Library 1.1.1
50303 * Copyright(c) 2006-2007, Ext JS, LLC.
50305 * Originally Released Under LGPL - original licence link has changed is not relivant.
50308 * <script type="text/javascript">
50311 // private - not really -- you end up using it !
50312 // This is a support class used internally by the Grid components
50315 * @class Roo.grid.GridEditor
50316 * @extends Roo.Editor
50317 * Class for creating and editable grid elements.
50318 * @param {Object} config any settings (must include field)
50320 Roo.grid.GridEditor = function(field, config){
50321 if (!config && field.field) {
50323 field = Roo.factory(config.field, Roo.form);
50325 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50326 field.monitorTab = false;
50329 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50332 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50335 alignment: "tl-tl",
50338 cls: "x-small-editor x-grid-editor",
50343 * Ext JS Library 1.1.1
50344 * Copyright(c) 2006-2007, Ext JS, LLC.
50346 * Originally Released Under LGPL - original licence link has changed is not relivant.
50349 * <script type="text/javascript">
50354 Roo.grid.PropertyRecord = Roo.data.Record.create([
50355 {name:'name',type:'string'}, 'value'
50359 Roo.grid.PropertyStore = function(grid, source){
50361 this.store = new Roo.data.Store({
50362 recordType : Roo.grid.PropertyRecord
50364 this.store.on('update', this.onUpdate, this);
50366 this.setSource(source);
50368 Roo.grid.PropertyStore.superclass.constructor.call(this);
50373 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50374 setSource : function(o){
50376 this.store.removeAll();
50379 if(this.isEditableValue(o[k])){
50380 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50383 this.store.loadRecords({records: data}, {}, true);
50386 onUpdate : function(ds, record, type){
50387 if(type == Roo.data.Record.EDIT){
50388 var v = record.data['value'];
50389 var oldValue = record.modified['value'];
50390 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50391 this.source[record.id] = v;
50393 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50400 getProperty : function(row){
50401 return this.store.getAt(row);
50404 isEditableValue: function(val){
50405 if(val && val instanceof Date){
50407 }else if(typeof val == 'object' || typeof val == 'function'){
50413 setValue : function(prop, value){
50414 this.source[prop] = value;
50415 this.store.getById(prop).set('value', value);
50418 getSource : function(){
50419 return this.source;
50423 Roo.grid.PropertyColumnModel = function(grid, store){
50426 g.PropertyColumnModel.superclass.constructor.call(this, [
50427 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50428 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50430 this.store = store;
50431 this.bselect = Roo.DomHelper.append(document.body, {
50432 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50433 {tag: 'option', value: 'true', html: 'true'},
50434 {tag: 'option', value: 'false', html: 'false'}
50437 Roo.id(this.bselect);
50440 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50441 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50442 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50443 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50444 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50446 this.renderCellDelegate = this.renderCell.createDelegate(this);
50447 this.renderPropDelegate = this.renderProp.createDelegate(this);
50450 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50454 valueText : 'Value',
50456 dateFormat : 'm/j/Y',
50459 renderDate : function(dateVal){
50460 return dateVal.dateFormat(this.dateFormat);
50463 renderBool : function(bVal){
50464 return bVal ? 'true' : 'false';
50467 isCellEditable : function(colIndex, rowIndex){
50468 return colIndex == 1;
50471 getRenderer : function(col){
50473 this.renderCellDelegate : this.renderPropDelegate;
50476 renderProp : function(v){
50477 return this.getPropertyName(v);
50480 renderCell : function(val){
50482 if(val instanceof Date){
50483 rv = this.renderDate(val);
50484 }else if(typeof val == 'boolean'){
50485 rv = this.renderBool(val);
50487 return Roo.util.Format.htmlEncode(rv);
50490 getPropertyName : function(name){
50491 var pn = this.grid.propertyNames;
50492 return pn && pn[name] ? pn[name] : name;
50495 getCellEditor : function(colIndex, rowIndex){
50496 var p = this.store.getProperty(rowIndex);
50497 var n = p.data['name'], val = p.data['value'];
50499 if(typeof(this.grid.customEditors[n]) == 'string'){
50500 return this.editors[this.grid.customEditors[n]];
50502 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50503 return this.grid.customEditors[n];
50505 if(val instanceof Date){
50506 return this.editors['date'];
50507 }else if(typeof val == 'number'){
50508 return this.editors['number'];
50509 }else if(typeof val == 'boolean'){
50510 return this.editors['boolean'];
50512 return this.editors['string'];
50518 * @class Roo.grid.PropertyGrid
50519 * @extends Roo.grid.EditorGrid
50520 * This class represents the interface of a component based property grid control.
50521 * <br><br>Usage:<pre><code>
50522 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50530 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50531 * The container MUST have some type of size defined for the grid to fill. The container will be
50532 * automatically set to position relative if it isn't already.
50533 * @param {Object} config A config object that sets properties on this grid.
50535 Roo.grid.PropertyGrid = function(container, config){
50536 config = config || {};
50537 var store = new Roo.grid.PropertyStore(this);
50538 this.store = store;
50539 var cm = new Roo.grid.PropertyColumnModel(this, store);
50540 store.store.sort('name', 'ASC');
50541 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50544 enableColLock:false,
50545 enableColumnMove:false,
50547 trackMouseOver: false,
50550 this.getGridEl().addClass('x-props-grid');
50551 this.lastEditRow = null;
50552 this.on('columnresize', this.onColumnResize, this);
50555 * @event beforepropertychange
50556 * Fires before a property changes (return false to stop?)
50557 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50558 * @param {String} id Record Id
50559 * @param {String} newval New Value
50560 * @param {String} oldval Old Value
50562 "beforepropertychange": true,
50564 * @event propertychange
50565 * Fires after a property changes
50566 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50567 * @param {String} id Record Id
50568 * @param {String} newval New Value
50569 * @param {String} oldval Old Value
50571 "propertychange": true
50573 this.customEditors = this.customEditors || {};
50575 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50578 * @cfg {Object} customEditors map of colnames=> custom editors.
50579 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50580 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50581 * false disables editing of the field.
50585 * @cfg {Object} propertyNames map of property Names to their displayed value
50588 render : function(){
50589 Roo.grid.PropertyGrid.superclass.render.call(this);
50590 this.autoSize.defer(100, this);
50593 autoSize : function(){
50594 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50596 this.view.fitColumns();
50600 onColumnResize : function(){
50601 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
50605 * Sets the data for the Grid
50606 * accepts a Key => Value object of all the elements avaiable.
50607 * @param {Object} data to appear in grid.
50609 setSource : function(source){
50610 this.store.setSource(source);
50614 * Gets all the data from the grid.
50615 * @return {Object} data data stored in grid
50617 getSource : function(){
50618 return this.store.getSource();
50622 * Ext JS Library 1.1.1
50623 * Copyright(c) 2006-2007, Ext JS, LLC.
50625 * Originally Released Under LGPL - original licence link has changed is not relivant.
50628 * <script type="text/javascript">
50632 * @class Roo.LoadMask
50633 * A simple utility class for generically masking elements while loading data. If the element being masked has
50634 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
50635 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
50636 * element's UpdateManager load indicator and will be destroyed after the initial load.
50638 * Create a new LoadMask
50639 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
50640 * @param {Object} config The config object
50642 Roo.LoadMask = function(el, config){
50643 this.el = Roo.get(el);
50644 Roo.apply(this, config);
50646 this.store.on('beforeload', this.onBeforeLoad, this);
50647 this.store.on('load', this.onLoad, this);
50648 this.store.on('loadexception', this.onLoad, this);
50649 this.removeMask = false;
50651 var um = this.el.getUpdateManager();
50652 um.showLoadIndicator = false; // disable the default indicator
50653 um.on('beforeupdate', this.onBeforeLoad, this);
50654 um.on('update', this.onLoad, this);
50655 um.on('failure', this.onLoad, this);
50656 this.removeMask = true;
50660 Roo.LoadMask.prototype = {
50662 * @cfg {Boolean} removeMask
50663 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
50664 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
50667 * @cfg {String} msg
50668 * The text to display in a centered loading message box (defaults to 'Loading...')
50670 msg : 'Loading...',
50672 * @cfg {String} msgCls
50673 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
50675 msgCls : 'x-mask-loading',
50678 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
50684 * Disables the mask to prevent it from being displayed
50686 disable : function(){
50687 this.disabled = true;
50691 * Enables the mask so that it can be displayed
50693 enable : function(){
50694 this.disabled = false;
50698 onLoad : function(){
50699 this.el.unmask(this.removeMask);
50703 onBeforeLoad : function(){
50704 if(!this.disabled){
50705 this.el.mask(this.msg, this.msgCls);
50710 destroy : function(){
50712 this.store.un('beforeload', this.onBeforeLoad, this);
50713 this.store.un('load', this.onLoad, this);
50714 this.store.un('loadexception', this.onLoad, this);
50716 var um = this.el.getUpdateManager();
50717 um.un('beforeupdate', this.onBeforeLoad, this);
50718 um.un('update', this.onLoad, this);
50719 um.un('failure', this.onLoad, this);
50724 * Ext JS Library 1.1.1
50725 * Copyright(c) 2006-2007, Ext JS, LLC.
50727 * Originally Released Under LGPL - original licence link has changed is not relivant.
50730 * <script type="text/javascript">
50732 Roo.XTemplate = function(){
50733 Roo.XTemplate.superclass.constructor.apply(this, arguments);
50736 s = ['<tpl>', s, '</tpl>'].join('');
50738 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
50740 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
50741 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
50742 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
50746 while(m = s.match(re)){
50747 var m2 = m[0].match(nameRe);
50748 var m3 = m[0].match(ifRe);
50749 var m4 = m[0].match(execRe);
50750 var exp = null, fn = null, exec = null;
50751 var name = m2 && m2[1] ? m2[1] : '';
50753 exp = m3 && m3[1] ? m3[1] : null;
50755 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
50759 exp = m4 && m4[1] ? m4[1] : null;
50761 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
50766 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
50767 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
50768 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
50778 s = s.replace(m[0], '{xtpl'+ id + '}');
50781 for(var i = tpls.length-1; i >= 0; --i){
50782 this.compileTpl(tpls[i]);
50784 this.master = tpls[tpls.length-1];
50787 Roo.extend(Roo.XTemplate, Roo.Template, {
50789 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
50791 applySubTemplate : function(id, values, parent){
50792 var t = this.tpls[id];
50793 if(t.test && !t.test.call(this, values, parent)){
50796 if(t.exec && t.exec.call(this, values, parent)){
50799 var vs = t.target ? t.target.call(this, values, parent) : values;
50800 parent = t.target ? values : parent;
50801 if(t.target && vs instanceof Array){
50803 for(var i = 0, len = vs.length; i < len; i++){
50804 buf[buf.length] = t.compiled.call(this, vs[i], parent);
50806 return buf.join('');
50808 return t.compiled.call(this, vs, parent);
50811 compileTpl : function(tpl){
50812 var fm = Roo.util.Format;
50813 var useF = this.disableFormats !== true;
50814 var sep = Roo.isGecko ? "+" : ",";
50815 var fn = function(m, name, format, args){
50816 if(name.substr(0, 4) == 'xtpl'){
50817 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
50820 if(name.indexOf('.') != -1){
50823 v = "values['" + name + "']";
50825 if(format && useF){
50826 args = args ? ',' + args : "";
50827 if(format.substr(0, 5) != "this."){
50828 format = "fm." + format + '(';
50830 format = 'this.call("'+ format.substr(5) + '", ';
50834 args= ''; format = "("+v+" === undefined ? '' : ";
50836 return "'"+ sep + format + v + args + ")"+sep+"'";
50839 // branched to use + in gecko and [].join() in others
50841 body = "tpl.compiled = function(values, parent){ return '" +
50842 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
50845 body = ["tpl.compiled = function(values, parent){ return ['"];
50846 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
50847 body.push("'].join('');};");
50848 body = body.join('');
50850 /** eval:var:zzzzzzz */
50855 applyTemplate : function(values){
50856 return this.master.compiled.call(this, values, {});
50860 apply : function(){
50861 return this.applyTemplate.apply(this, arguments);
50864 compile : function(){return this;}
50867 Roo.XTemplate.from = function(el){
50868 el = Roo.getDom(el);
50869 return new Roo.XTemplate(el.value || el.innerHTML);
50871 * Original code for Roojs - LGPL
50872 * <script type="text/javascript">
50876 * @class Roo.XComponent
50877 * A delayed Element creator...
50879 * Mypart.xyx = new Roo.XComponent({
50881 parent : 'Mypart.xyz', // empty == document.element.!!
50885 disabled : function() {}
50887 tree : function() { // return an tree of xtype declared components
50891 xtype : 'NestedLayoutPanel',
50896 * @extends Roo.util.Observable
50898 * @param cfg {Object} configuration of component
50901 Roo.XComponent = function(cfg) {
50902 Roo.apply(this, cfg);
50906 * Fires when this the componnt is built
50907 * @param {Roo.XComponent} c the component
50911 * @event buildcomplete
50912 * Fires on the top level element when all elements have been built
50913 * @param {Roo.XComponent} c the top level component.
50915 'buildcomplete' : true
50919 Roo.XComponent.register(this);
50920 this.modules = false;
50921 this.el = false; // where the layout goes..
50925 Roo.extend(Roo.XComponent, Roo.util.Observable, {
50928 * The created element (with Roo.factory())
50929 * @type {Roo.Layout}
50935 * for BC - use el in new code
50936 * @type {Roo.Layout}
50942 * for BC - use el in new code
50943 * @type {Roo.Layout}
50948 * @cfg {Function|boolean} disabled
50949 * If this module is disabled by some rule, return true from the funtion
50954 * @cfg {String} parent
50955 * Name of parent element which it get xtype added to..
50960 * @cfg {String} order
50961 * Used to set the order in which elements are created (usefull for multiple tabs)
50966 * @cfg {String} name
50967 * String to display while loading.
50971 * @cfg {Array} items
50972 * A single item array - the first element is the root of the tree..
50973 * It's done this way to stay compatible with the Xtype system...
50981 Roo.apply(Roo.XComponent, {
50984 * @property buildCompleted
50985 * True when the builder has completed building the interface.
50988 buildCompleted : false,
50991 * @property topModule
50992 * the upper most module - uses document.element as it's constructor.
50999 * @property modules
51000 * array of modules to be created by registration system.
51001 * @type Roo.XComponent
51008 * Register components to be built later.
51010 * This solves the following issues
51011 * - Building is not done on page load, but after an authentication process has occured.
51012 * - Interface elements are registered on page load
51013 * - Parent Interface elements may not be loaded before child, so this handles that..
51020 module : 'Pman.Tab.projectMgr',
51022 parent : 'Pman.layout',
51023 disabled : false, // or use a function..
51026 * * @param {Object} details about module
51028 register : function(obj) {
51029 this.modules.push(obj);
51033 * convert a string to an object..
51037 toObject : function(str)
51039 if (!str || typeof(str) == 'object') {
51042 var ar = str.split('.');
51046 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51048 throw "Module not found : " + str;
51050 Roo.each(ar, function(e) {
51051 if (typeof(o[e]) == 'undefined') {
51052 throw "Module not found : " + str;
51062 * move modules into their correct place in the tree..
51065 preBuild : function ()
51068 Roo.each(this.modules , function (obj)
51070 obj.parent = this.toObject(obj.parent);
51073 this.topModule = obj;
51077 if (!obj.parent.modules) {
51078 obj.parent.modules = new Roo.util.MixedCollection(false,
51079 function(o) { return o.order + '' }
51083 obj.parent.modules.add(obj);
51088 * make a list of modules to build.
51089 * @return {Array} list of modules.
51092 buildOrder : function()
51095 var cmp = function(a,b) {
51096 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51099 if (!this.topModule || !this.topModule.modules) {
51100 throw "No top level modules to build";
51103 // make a flat list in order of modules to build.
51104 var mods = [ this.topModule ];
51107 // add modules to their parents..
51108 var addMod = function(m) {
51109 // Roo.debug && Roo.log(m.modKey);
51113 m.modules.keySort('ASC', cmp );
51114 m.modules.each(addMod);
51116 // not sure if this is used any more..
51118 m.finalize.name = m.name + " (clean up) ";
51119 mods.push(m.finalize);
51123 this.topModule.modules.keySort('ASC', cmp );
51124 this.topModule.modules.each(addMod);
51129 * Build the registered modules.
51130 * @param {Object} parent element.
51131 * @param {Function} optional method to call after module has been added.
51139 var mods = this.buildOrder();
51141 //this.allmods = mods;
51142 //Roo.debug && Roo.log(mods);
51144 if (!mods.length) { // should not happen
51145 throw "NO modules!!!";
51150 // flash it up as modal - so we store the mask!?
51151 Roo.MessageBox.show({ title: 'loading' });
51152 Roo.MessageBox.show({
51153 title: "Please wait...",
51154 msg: "Building Interface...",
51161 var total = mods.length;
51164 var progressRun = function() {
51165 if (!mods.length) {
51166 Roo.debug && Roo.log('hide?');
51167 Roo.MessageBox.hide();
51168 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51172 var m = mods.shift();
51173 Roo.debug && Roo.log(m);
51174 if (typeof(m) == 'function') { // not sure if this is supported any more..
51176 return progressRun.defer(10, _this);
51179 Roo.MessageBox.updateProgress(
51180 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51182 (m.name ? (' - ' + m.name) : '')
51187 var disabled = (typeof(m.disabled) == 'function') ?
51188 m.disabled.call(m.module.disabled) : m.disabled;
51192 return progressRun(); // we do not update the display!
51196 // it's a top level one..
51197 var layoutbase = new Ext.BorderLayout(document.body, {
51203 tabPosition: 'top',
51204 //resizeTabs: true,
51205 alwaysShowTabs: true,
51209 var tree = m.tree();
51210 tree.region = 'center';
51211 m.el = layoutbase.addxtype(tree);
51213 m.layout = m.panel.layout;
51214 return progressRun.defer(10, _this);
51217 var tree = m.tree();
51218 tree.region = tree.region || m.region;
51219 m.el = m.parent.el.addxtype(tree);
51220 m.fireEvent('built', m);
51222 m.layout = m.panel.layout;
51223 progressRun.defer(10, _this);
51226 progressRun.defer(1, _this);
51236 //<script type="text/javascript">
51241 * @extends Roo.LayoutDialog
51242 * A generic Login Dialog..... - only one needed in theory!?!?
51244 * Fires XComponent builder on success...
51247 * username,password, lang = for login actions.
51248 * check = 1 for periodic checking that sesion is valid.
51249 * passwordRequest = email request password
51250 * logout = 1 = to logout
51252 * Affects: (this id="????" elements)
51253 * loading (removed) (used to indicate application is loading)
51254 * loading-mask (hides) (used to hide application when it's building loading)
51260 * Myapp.login = Roo.Login({
51276 Roo.Login = function(cfg)
51282 Roo.apply(this,cfg);
51284 Roo.onReady(function() {
51290 Roo.Login.superclass.constructor.call(this, this);
51291 //this.addxtype(this.items[0]);
51297 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51300 * @cfg {String} method
51301 * Method used to query for login details.
51306 * @cfg {String} url
51307 * URL to query login data. - eg. baseURL + '/Login.php'
51313 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51318 * @property checkFails
51319 * Number of times we have attempted to get authentication check, and failed.
51324 * @property intervalID
51325 * The window interval that does the constant login checking.
51331 onLoad : function() // called on page load...
51335 if (Roo.get('loading')) { // clear any loading indicator..
51336 Roo.get('loading').remove();
51339 //this.switchLang('en'); // set the language to english..
51342 success: function(response, opts) { // check successfull...
51344 var res = this.processResponse(response);
51345 this.checkFails =0;
51346 if (!res.success) { // error!
51347 this.checkFails = 5;
51348 //console.log('call failure');
51349 return this.failure(response,opts);
51352 if (!res.data.id) { // id=0 == login failure.
51353 return this.show();
51357 //console.log(success);
51358 this.fillAuth(res.data);
51359 this.checkFails =0;
51360 Roo.XComponent.build();
51362 failure : this.show
51368 check: function(cfg) // called every so often to refresh cookie etc..
51370 if (cfg.again) { // could be undefined..
51373 this.checkFails = 0;
51376 if (this.sending) {
51377 if ( this.checkFails > 4) {
51378 Roo.MessageBox.alert("Error",
51379 "Error getting authentication status. - try reloading, or wait a while", function() {
51380 _this.sending = false;
51385 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51388 this.sending = true;
51395 method: this.method,
51396 success: cfg.success || this.success,
51397 failure : cfg.failure || this.failure,
51407 window.onbeforeunload = function() { }; // false does not work for IE..
51417 failure : function() {
51418 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51419 document.location = document.location.toString() + '?ts=' + Math.random();
51423 success : function() {
51424 _this.user = false;
51425 this.checkFails =0;
51427 document.location = document.location.toString() + '?ts=' + Math.random();
51434 processResponse : function (response)
51438 res = Roo.decode(response.responseText);
51440 if (typeof(res) != 'object') {
51441 res = { success : false, errorMsg : res, errors : true };
51443 if (typeof(res.success) == 'undefined') {
51444 res.success = false;
51448 res = { success : false, errorMsg : response.responseText, errors : true };
51453 success : function(response, opts) // check successfull...
51455 this.sending = false;
51456 var res = this.processResponse(response);
51457 if (!res.success) {
51458 return this.failure(response, opts);
51460 if (!res.data || !res.data.id) {
51461 return this.failure(response,opts);
51463 //console.log(res);
51464 this.fillAuth(res.data);
51466 this.checkFails =0;
51471 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51473 this.authUser = -1;
51474 this.sending = false;
51475 var res = this.processResponse(response);
51476 //console.log(res);
51477 if ( this.checkFails > 2) {
51479 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51480 "Error getting authentication status. - try reloading");
51483 opts.callCfg.again = true;
51484 this.check.defer(1000, this, [ opts.callCfg ]);
51490 fillAuth: function(au) {
51491 this.startAuthCheck();
51492 this.authUserId = au.id;
51493 this.authUser = au;
51494 this.lastChecked = new Date();
51495 this.fireEvent('refreshed', au);
51496 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
51497 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
51498 au.lang = au.lang || 'en';
51499 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
51500 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
51501 this.switchLang(au.lang );
51504 // open system... - -on setyp..
51505 if (this.authUserId < 0) {
51506 Roo.MessageBox.alert("Warning",
51507 "This is an open system - please set up a admin user with a password.");
51510 //Pman.onload(); // which should do nothing if it's a re-auth result...
51515 startAuthCheck : function() // starter for timeout checking..
51517 if (this.intervalID) { // timer already in place...
51521 this.intervalID = window.setInterval(function() {
51522 _this.check(false);
51523 }, 120000); // every 120 secs = 2mins..
51529 switchLang : function (lang)
51531 _T = typeof(_T) == 'undefined' ? false : _T;
51532 if (!_T || !lang.length) {
51536 if (!_T && lang != 'en') {
51537 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51541 if (typeof(_T.en) == 'undefined') {
51543 Roo.apply(_T.en, _T);
51546 if (typeof(_T[lang]) == 'undefined') {
51547 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51552 Roo.apply(_T, _T[lang]);
51553 // just need to set the text values for everything...
51555 /* this will not work ...
51559 function formLabel(name, val) {
51560 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
51563 formLabel('password', "Password"+':');
51564 formLabel('username', "Email Address"+':');
51565 formLabel('lang', "Language"+':');
51566 this.dialog.setTitle("Login");
51567 this.dialog.buttons[0].setText("Forgot Password");
51568 this.dialog.buttons[1].setText("Login");
51587 collapsible: false,
51589 center: { // needed??
51592 // tabPosition: 'top',
51595 alwaysShowTabs: false
51599 show : function(dlg)
51601 //console.log(this);
51602 this.form = this.layout.getRegion('center').activePanel.form;
51603 this.form.dialog = dlg;
51604 this.buttons[0].form = this.form;
51605 this.buttons[0].dialog = dlg;
51606 this.buttons[1].form = this.form;
51607 this.buttons[1].dialog = dlg;
51609 //this.resizeToLogo.defer(1000,this);
51610 // this is all related to resizing for logos..
51611 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
51613 // this.resizeToLogo.defer(1000,this);
51616 //var w = Ext.lib.Dom.getViewWidth() - 100;
51617 //var h = Ext.lib.Dom.getViewHeight() - 100;
51618 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
51620 if (this.disabled) {
51625 if (this.user.id < 0) { // used for inital setup situations.
51629 if (this.intervalID) {
51630 // remove the timer
51631 window.clearInterval(this.intervalID);
51632 this.intervalID = false;
51636 if (Roo.get('loading')) {
51637 Roo.get('loading').remove();
51639 if (Roo.get('loading-mask')) {
51640 Roo.get('loading-mask').hide();
51643 //incomming._node = tnode;
51645 //this.dialog.modal = !modal;
51646 //this.dialog.show();
51650 this.form.setValues({
51651 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
51652 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
51655 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
51656 if (this.form.findField('username').getValue().length > 0 ){
51657 this.form.findField('password').focus();
51659 this.form.findField('username').focus();
51667 xtype : 'ContentPanel',
51679 style : 'margin: 10px;',
51682 actionfailed : function(f, act) {
51683 // form can return { errors: .... }
51685 //act.result.errors // invalid form element list...
51686 //act.result.errorMsg// invalid form element list...
51688 this.dialog.el.unmask();
51689 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
51690 "Login failed - communication error - try again.");
51693 actioncomplete: function(re, act) {
51695 Roo.state.Manager.set(
51696 this.dialog.realm + '.username',
51697 this.findField('username').getValue()
51699 Roo.state.Manager.set(
51700 this.dialog.realm + '.lang',
51701 this.findField('lang').getValue()
51704 this.dialog.fillAuth(act.result.data);
51706 this.dialog.hide();
51708 if (Roo.get('loading-mask')) {
51709 Roo.get('loading-mask').show();
51711 Roo.XComponent.build();
51719 xtype : 'TextField',
51721 fieldLabel: "Email Address",
51724 autoCreate : {tag: "input", type: "text", size: "20"}
51727 xtype : 'TextField',
51729 fieldLabel: "Password",
51730 inputType: 'password',
51733 autoCreate : {tag: "input", type: "text", size: "20"},
51735 specialkey : function(e,ev) {
51736 if (ev.keyCode == 13) {
51737 this.form.dialog.el.mask("Logging in");
51738 this.form.doAction('submit', {
51739 url: this.form.dialog.url,
51740 method: this.form.dialog.method
51747 xtype : 'ComboBox',
51749 fieldLabel: "Language",
51752 xtype : 'SimpleStore',
51753 fields: ['lang', 'ldisp'],
51755 [ 'en', 'English' ],
51756 [ 'zh_HK' , '\u7E41\u4E2D' ],
51757 [ 'zh_CN', '\u7C21\u4E2D' ]
51761 valueField : 'lang',
51762 hiddenName: 'lang',
51764 displayField:'ldisp',
51768 triggerAction: 'all',
51769 emptyText:'Select a Language...',
51770 selectOnFocus:true,
51772 select : function(cb, rec, ix) {
51773 this.form.switchLang(rec.data.lang);
51789 text : "Forgot Password",
51791 click : function() {
51792 //console.log(this);
51793 var n = this.form.findField('username').getValue();
51795 Roo.MessageBox.alert("Error", "Fill in your email address");
51799 url: this.dialog.url,
51803 method: this.dialog.method,
51804 success: function(response, opts) { // check successfull...
51806 var res = this.dialog.processResponse(response);
51807 if (!res.success) { // error!
51808 Roo.MessageBox.alert("Error" ,
51809 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
51812 Roo.MessageBox.alert("Notice" ,
51813 "Please check you email for the Password Reset message");
51815 failure : function() {
51816 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
51829 click : function () {
51831 this.dialog.el.mask("Logging in");
51832 this.form.doAction('submit', {
51833 url: this.dialog.url,
51834 method: this.dialog.method