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 (add/sub/ok/nodrop)
18397 * if the drop point is valid for over/enter..
18404 isNotifyTarget : true,
18409 notifyEnter : function(dd, e, data){
18411 this.fireEvent('enter', dd, e, data);
18412 if(this.overClass){
18413 this.el.addClass(this.overClass);
18415 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18416 this.valid ? this.dropAllowed : this.dropNotAllowed
18423 notifyOver : function(dd, e, data){
18425 this.fireEvent('over', dd, e, data);
18426 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18427 this.valid ? this.dropAllowed : this.dropNotAllowed
18434 notifyOut : function(dd, e, data){
18435 this.fireEvent('out', dd, e, data);
18436 if(this.overClass){
18437 this.el.removeClass(this.overClass);
18444 notifyDrop : function(dd, e, data){
18445 this.success = false;
18446 this.fireEvent('drop', dd, e, data);
18447 return this.success;
18451 * Ext JS Library 1.1.1
18452 * Copyright(c) 2006-2007, Ext JS, LLC.
18454 * Originally Released Under LGPL - original licence link has changed is not relivant.
18457 * <script type="text/javascript">
18462 * @class Roo.dd.DragZone
18463 * @extends Roo.dd.DragSource
18464 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18465 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18467 * @param {String/HTMLElement/Element} el The container element
18468 * @param {Object} config
18470 Roo.dd.DragZone = function(el, config){
18471 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18472 if(this.containerScroll){
18473 Roo.dd.ScrollManager.register(this.el);
18477 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18479 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18480 * for auto scrolling during drag operations.
18483 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18484 * method after a failed drop (defaults to "c3daf9" - light blue)
18488 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18489 * for a valid target to drag based on the mouse down. Override this method
18490 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18491 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18492 * @param {EventObject} e The mouse down event
18493 * @return {Object} The dragData
18495 getDragData : function(e){
18496 return Roo.dd.Registry.getHandleFromEvent(e);
18500 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18501 * this.dragData.ddel
18502 * @param {Number} x The x position of the click on the dragged object
18503 * @param {Number} y The y position of the click on the dragged object
18504 * @return {Boolean} true to continue the drag, false to cancel
18506 onInitDrag : function(x, y){
18507 this.proxy.update(this.dragData.ddel.cloneNode(true));
18508 this.onStartDrag(x, y);
18513 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18515 afterRepair : function(){
18517 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18519 this.dragging = false;
18523 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18524 * the XY of this.dragData.ddel
18525 * @param {EventObject} e The mouse up event
18526 * @return {Array} The xy location (e.g. [100, 200])
18528 getRepairXY : function(e){
18529 return Roo.Element.fly(this.dragData.ddel).getXY();
18533 * Ext JS Library 1.1.1
18534 * Copyright(c) 2006-2007, Ext JS, LLC.
18536 * Originally Released Under LGPL - original licence link has changed is not relivant.
18539 * <script type="text/javascript">
18542 * @class Roo.dd.DropZone
18543 * @extends Roo.dd.DropTarget
18544 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18545 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18547 * @param {String/HTMLElement/Element} el The container element
18548 * @param {Object} config
18550 Roo.dd.DropZone = function(el, config){
18551 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18554 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18556 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18557 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18558 * provide your own custom lookup.
18559 * @param {Event} e The event
18560 * @return {Object} data The custom data
18562 getTargetFromEvent : function(e){
18563 return Roo.dd.Registry.getTargetFromEvent(e);
18567 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18568 * that it has registered. This method has no default implementation and should be overridden to provide
18569 * node-specific processing if necessary.
18570 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18571 * {@link #getTargetFromEvent} for this node)
18572 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18573 * @param {Event} e The event
18574 * @param {Object} data An object containing arbitrary data supplied by the drag source
18576 onNodeEnter : function(n, dd, e, data){
18581 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18582 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18583 * overridden to provide the proper feedback.
18584 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18585 * {@link #getTargetFromEvent} for this node)
18586 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18587 * @param {Event} e The event
18588 * @param {Object} data An object containing arbitrary data supplied by the drag source
18589 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18590 * underlying {@link Roo.dd.StatusProxy} can be updated
18592 onNodeOver : function(n, dd, e, data){
18593 return this.dropAllowed;
18597 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18598 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18599 * node-specific processing if necessary.
18600 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18601 * {@link #getTargetFromEvent} for this node)
18602 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18603 * @param {Event} e The event
18604 * @param {Object} data An object containing arbitrary data supplied by the drag source
18606 onNodeOut : function(n, dd, e, data){
18611 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18612 * the drop node. The default implementation returns false, so it should be overridden to provide the
18613 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18614 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18615 * {@link #getTargetFromEvent} for this node)
18616 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18617 * @param {Event} e The event
18618 * @param {Object} data An object containing arbitrary data supplied by the drag source
18619 * @return {Boolean} True if the drop was valid, else false
18621 onNodeDrop : function(n, dd, e, data){
18626 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18627 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18628 * it should be overridden to provide the proper feedback if necessary.
18629 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18630 * @param {Event} e The event
18631 * @param {Object} data An object containing arbitrary data supplied by the drag source
18632 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18633 * underlying {@link Roo.dd.StatusProxy} can be updated
18635 onContainerOver : function(dd, e, data){
18636 return this.dropNotAllowed;
18640 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18641 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18642 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18643 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18644 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18645 * @param {Event} e The event
18646 * @param {Object} data An object containing arbitrary data supplied by the drag source
18647 * @return {Boolean} True if the drop was valid, else false
18649 onContainerDrop : function(dd, e, data){
18654 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18655 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18656 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18657 * you should override this method and provide a custom implementation.
18658 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18659 * @param {Event} e The event
18660 * @param {Object} data An object containing arbitrary data supplied by the drag source
18661 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18662 * underlying {@link Roo.dd.StatusProxy} can be updated
18664 notifyEnter : function(dd, e, data){
18665 return this.dropNotAllowed;
18669 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18670 * This method will be called on every mouse movement while the drag source is over the drop zone.
18671 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18672 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18673 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18674 * registered node, it will call {@link #onContainerOver}.
18675 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18676 * @param {Event} e The event
18677 * @param {Object} data An object containing arbitrary data supplied by the drag source
18678 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18679 * underlying {@link Roo.dd.StatusProxy} can be updated
18681 notifyOver : function(dd, e, data){
18682 var n = this.getTargetFromEvent(e);
18683 if(!n){ // not over valid drop target
18684 if(this.lastOverNode){
18685 this.onNodeOut(this.lastOverNode, dd, e, data);
18686 this.lastOverNode = null;
18688 return this.onContainerOver(dd, e, data);
18690 if(this.lastOverNode != n){
18691 if(this.lastOverNode){
18692 this.onNodeOut(this.lastOverNode, dd, e, data);
18694 this.onNodeEnter(n, dd, e, data);
18695 this.lastOverNode = n;
18697 return this.onNodeOver(n, dd, e, data);
18701 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18702 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18703 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18704 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18705 * @param {Event} e The event
18706 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18708 notifyOut : function(dd, e, data){
18709 if(this.lastOverNode){
18710 this.onNodeOut(this.lastOverNode, dd, e, data);
18711 this.lastOverNode = null;
18716 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18717 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18718 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18719 * otherwise it will call {@link #onContainerDrop}.
18720 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18721 * @param {Event} e The event
18722 * @param {Object} data An object containing arbitrary data supplied by the drag source
18723 * @return {Boolean} True if the drop was valid, else false
18725 notifyDrop : function(dd, e, data){
18726 if(this.lastOverNode){
18727 this.onNodeOut(this.lastOverNode, dd, e, data);
18728 this.lastOverNode = null;
18730 var n = this.getTargetFromEvent(e);
18732 this.onNodeDrop(n, dd, e, data) :
18733 this.onContainerDrop(dd, e, data);
18737 triggerCacheRefresh : function(){
18738 Roo.dd.DDM.refreshCache(this.groups);
18742 * Ext JS Library 1.1.1
18743 * Copyright(c) 2006-2007, Ext JS, LLC.
18745 * Originally Released Under LGPL - original licence link has changed is not relivant.
18748 * <script type="text/javascript">
18753 * @class Roo.data.SortTypes
18755 * Defines the default sorting (casting?) comparison functions used when sorting data.
18757 Roo.data.SortTypes = {
18759 * Default sort that does nothing
18760 * @param {Mixed} s The value being converted
18761 * @return {Mixed} The comparison value
18763 none : function(s){
18768 * The regular expression used to strip tags
18772 stripTagsRE : /<\/?[^>]+>/gi,
18775 * Strips all HTML tags to sort on text only
18776 * @param {Mixed} s The value being converted
18777 * @return {String} The comparison value
18779 asText : function(s){
18780 return String(s).replace(this.stripTagsRE, "");
18784 * Strips all HTML tags to sort on text only - Case insensitive
18785 * @param {Mixed} s The value being converted
18786 * @return {String} The comparison value
18788 asUCText : function(s){
18789 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18793 * Case insensitive string
18794 * @param {Mixed} s The value being converted
18795 * @return {String} The comparison value
18797 asUCString : function(s) {
18798 return String(s).toUpperCase();
18803 * @param {Mixed} s The value being converted
18804 * @return {Number} The comparison value
18806 asDate : function(s) {
18810 if(s instanceof Date){
18811 return s.getTime();
18813 return Date.parse(String(s));
18818 * @param {Mixed} s The value being converted
18819 * @return {Float} The comparison value
18821 asFloat : function(s) {
18822 var val = parseFloat(String(s).replace(/,/g, ""));
18823 if(isNaN(val)) val = 0;
18829 * @param {Mixed} s The value being converted
18830 * @return {Number} The comparison value
18832 asInt : function(s) {
18833 var val = parseInt(String(s).replace(/,/g, ""));
18834 if(isNaN(val)) val = 0;
18839 * Ext JS Library 1.1.1
18840 * Copyright(c) 2006-2007, Ext JS, LLC.
18842 * Originally Released Under LGPL - original licence link has changed is not relivant.
18845 * <script type="text/javascript">
18849 * @class Roo.data.Record
18850 * Instances of this class encapsulate both record <em>definition</em> information, and record
18851 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18852 * to access Records cached in an {@link Roo.data.Store} object.<br>
18854 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18855 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18858 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18860 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18861 * {@link #create}. The parameters are the same.
18862 * @param {Array} data An associative Array of data values keyed by the field name.
18863 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18864 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18865 * not specified an integer id is generated.
18867 Roo.data.Record = function(data, id){
18868 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18873 * Generate a constructor for a specific record layout.
18874 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18875 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18876 * Each field definition object may contain the following properties: <ul>
18877 * <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,
18878 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18879 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18880 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18881 * is being used, then this is a string containing the javascript expression to reference the data relative to
18882 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18883 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18884 * this may be omitted.</p></li>
18885 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18886 * <ul><li>auto (Default, implies no conversion)</li>
18891 * <li>date</li></ul></p></li>
18892 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18893 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18894 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18895 * by the Reader into an object that will be stored in the Record. It is passed the
18896 * following parameters:<ul>
18897 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18899 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18901 * <br>usage:<br><pre><code>
18902 var TopicRecord = Roo.data.Record.create(
18903 {name: 'title', mapping: 'topic_title'},
18904 {name: 'author', mapping: 'username'},
18905 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18906 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18907 {name: 'lastPoster', mapping: 'user2'},
18908 {name: 'excerpt', mapping: 'post_text'}
18911 var myNewRecord = new TopicRecord({
18912 title: 'Do my job please',
18915 lastPost: new Date(),
18916 lastPoster: 'Animal',
18917 excerpt: 'No way dude!'
18919 myStore.add(myNewRecord);
18924 Roo.data.Record.create = function(o){
18925 var f = function(){
18926 f.superclass.constructor.apply(this, arguments);
18928 Roo.extend(f, Roo.data.Record);
18929 var p = f.prototype;
18930 p.fields = new Roo.util.MixedCollection(false, function(field){
18933 for(var i = 0, len = o.length; i < len; i++){
18934 p.fields.add(new Roo.data.Field(o[i]));
18936 f.getField = function(name){
18937 return p.fields.get(name);
18942 Roo.data.Record.AUTO_ID = 1000;
18943 Roo.data.Record.EDIT = 'edit';
18944 Roo.data.Record.REJECT = 'reject';
18945 Roo.data.Record.COMMIT = 'commit';
18947 Roo.data.Record.prototype = {
18949 * Readonly flag - true if this record has been modified.
18958 join : function(store){
18959 this.store = store;
18963 * Set the named field to the specified value.
18964 * @param {String} name The name of the field to set.
18965 * @param {Object} value The value to set the field to.
18967 set : function(name, value){
18968 if(this.data[name] == value){
18972 if(!this.modified){
18973 this.modified = {};
18975 if(typeof this.modified[name] == 'undefined'){
18976 this.modified[name] = this.data[name];
18978 this.data[name] = value;
18980 this.store.afterEdit(this);
18985 * Get the value of the named field.
18986 * @param {String} name The name of the field to get the value of.
18987 * @return {Object} The value of the field.
18989 get : function(name){
18990 return this.data[name];
18994 beginEdit : function(){
18995 this.editing = true;
18996 this.modified = {};
19000 cancelEdit : function(){
19001 this.editing = false;
19002 delete this.modified;
19006 endEdit : function(){
19007 this.editing = false;
19008 if(this.dirty && this.store){
19009 this.store.afterEdit(this);
19014 * Usually called by the {@link Roo.data.Store} which owns the Record.
19015 * Rejects all changes made to the Record since either creation, or the last commit operation.
19016 * Modified fields are reverted to their original values.
19018 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19019 * of reject operations.
19021 reject : function(){
19022 var m = this.modified;
19024 if(typeof m[n] != "function"){
19025 this.data[n] = m[n];
19028 this.dirty = false;
19029 delete this.modified;
19030 this.editing = false;
19032 this.store.afterReject(this);
19037 * Usually called by the {@link Roo.data.Store} which owns the Record.
19038 * Commits all changes made to the Record since either creation, or the last commit operation.
19040 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19041 * of commit operations.
19043 commit : function(){
19044 this.dirty = false;
19045 delete this.modified;
19046 this.editing = false;
19048 this.store.afterCommit(this);
19053 hasError : function(){
19054 return this.error != null;
19058 clearError : function(){
19063 * Creates a copy of this record.
19064 * @param {String} id (optional) A new record id if you don't want to use this record's id
19067 copy : function(newId) {
19068 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19072 * Ext JS Library 1.1.1
19073 * Copyright(c) 2006-2007, Ext JS, LLC.
19075 * Originally Released Under LGPL - original licence link has changed is not relivant.
19078 * <script type="text/javascript">
19084 * @class Roo.data.Store
19085 * @extends Roo.util.Observable
19086 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19087 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19089 * 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
19090 * has no knowledge of the format of the data returned by the Proxy.<br>
19092 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19093 * instances from the data object. These records are cached and made available through accessor functions.
19095 * Creates a new Store.
19096 * @param {Object} config A config object containing the objects needed for the Store to access data,
19097 * and read the data into Records.
19099 Roo.data.Store = function(config){
19100 this.data = new Roo.util.MixedCollection(false);
19101 this.data.getKey = function(o){
19104 this.baseParams = {};
19106 this.paramNames = {
19113 if(config && config.data){
19114 this.inlineData = config.data;
19115 delete config.data;
19118 Roo.apply(this, config);
19120 if(this.reader){ // reader passed
19121 this.reader = Roo.factory(this.reader, Roo.data);
19122 this.reader.xmodule = this.xmodule || false;
19123 if(!this.recordType){
19124 this.recordType = this.reader.recordType;
19126 if(this.reader.onMetaChange){
19127 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19131 if(this.recordType){
19132 this.fields = this.recordType.prototype.fields;
19134 this.modified = [];
19138 * @event datachanged
19139 * Fires when the data cache has changed, and a widget which is using this Store
19140 * as a Record cache should refresh its view.
19141 * @param {Store} this
19143 datachanged : true,
19145 * @event metachange
19146 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19147 * @param {Store} this
19148 * @param {Object} meta The JSON metadata
19153 * Fires when Records have been added to the Store
19154 * @param {Store} this
19155 * @param {Roo.data.Record[]} records The array of Records added
19156 * @param {Number} index The index at which the record(s) were added
19161 * Fires when a Record has been removed from the Store
19162 * @param {Store} this
19163 * @param {Roo.data.Record} record The Record that was removed
19164 * @param {Number} index The index at which the record was removed
19169 * Fires when a Record has been updated
19170 * @param {Store} this
19171 * @param {Roo.data.Record} record The Record that was updated
19172 * @param {String} operation The update operation being performed. Value may be one of:
19174 Roo.data.Record.EDIT
19175 Roo.data.Record.REJECT
19176 Roo.data.Record.COMMIT
19182 * Fires when the data cache has been cleared.
19183 * @param {Store} this
19187 * @event beforeload
19188 * Fires before a request is made for a new data object. If the beforeload handler returns false
19189 * the load action will be canceled.
19190 * @param {Store} this
19191 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19196 * Fires after a new set of Records has been loaded.
19197 * @param {Store} this
19198 * @param {Roo.data.Record[]} records The Records that were loaded
19199 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19203 * @event loadexception
19204 * Fires if an exception occurs in the Proxy during loading.
19205 * Called with the signature of the Proxy's "loadexception" event.
19206 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19209 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19210 * @param {Object} load options
19211 * @param {Object} jsonData from your request (normally this contains the Exception)
19213 loadexception : true
19217 this.proxy = Roo.factory(this.proxy, Roo.data);
19218 this.proxy.xmodule = this.xmodule || false;
19219 this.relayEvents(this.proxy, ["loadexception"]);
19221 this.sortToggle = {};
19223 Roo.data.Store.superclass.constructor.call(this);
19225 if(this.inlineData){
19226 this.loadData(this.inlineData);
19227 delete this.inlineData;
19230 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19232 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19233 * without a remote query - used by combo/forms at present.
19237 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19240 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19243 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19244 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19247 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19248 * on any HTTP request
19251 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19254 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19255 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19257 remoteSort : false,
19260 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19261 * loaded or when a record is removed. (defaults to false).
19263 pruneModifiedRecords : false,
19266 lastOptions : null,
19269 * Add Records to the Store and fires the add event.
19270 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19272 add : function(records){
19273 records = [].concat(records);
19274 for(var i = 0, len = records.length; i < len; i++){
19275 records[i].join(this);
19277 var index = this.data.length;
19278 this.data.addAll(records);
19279 this.fireEvent("add", this, records, index);
19283 * Remove a Record from the Store and fires the remove event.
19284 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19286 remove : function(record){
19287 var index = this.data.indexOf(record);
19288 this.data.removeAt(index);
19289 if(this.pruneModifiedRecords){
19290 this.modified.remove(record);
19292 this.fireEvent("remove", this, record, index);
19296 * Remove all Records from the Store and fires the clear event.
19298 removeAll : function(){
19300 if(this.pruneModifiedRecords){
19301 this.modified = [];
19303 this.fireEvent("clear", this);
19307 * Inserts Records to the Store at the given index and fires the add event.
19308 * @param {Number} index The start index at which to insert the passed Records.
19309 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19311 insert : function(index, records){
19312 records = [].concat(records);
19313 for(var i = 0, len = records.length; i < len; i++){
19314 this.data.insert(index, records[i]);
19315 records[i].join(this);
19317 this.fireEvent("add", this, records, index);
19321 * Get the index within the cache of the passed Record.
19322 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19323 * @return {Number} The index of the passed Record. Returns -1 if not found.
19325 indexOf : function(record){
19326 return this.data.indexOf(record);
19330 * Get the index within the cache of the Record with the passed id.
19331 * @param {String} id The id of the Record to find.
19332 * @return {Number} The index of the Record. Returns -1 if not found.
19334 indexOfId : function(id){
19335 return this.data.indexOfKey(id);
19339 * Get the Record with the specified id.
19340 * @param {String} id The id of the Record to find.
19341 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19343 getById : function(id){
19344 return this.data.key(id);
19348 * Get the Record at the specified index.
19349 * @param {Number} index The index of the Record to find.
19350 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19352 getAt : function(index){
19353 return this.data.itemAt(index);
19357 * Returns a range of Records between specified indices.
19358 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19359 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19360 * @return {Roo.data.Record[]} An array of Records
19362 getRange : function(start, end){
19363 return this.data.getRange(start, end);
19367 storeOptions : function(o){
19368 o = Roo.apply({}, o);
19371 this.lastOptions = o;
19375 * Loads the Record cache from the configured Proxy using the configured Reader.
19377 * If using remote paging, then the first load call must specify the <em>start</em>
19378 * and <em>limit</em> properties in the options.params property to establish the initial
19379 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19381 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19382 * and this call will return before the new data has been loaded. Perform any post-processing
19383 * in a callback function, or in a "load" event handler.</strong>
19385 * @param {Object} options An object containing properties which control loading options:<ul>
19386 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19387 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19388 * passed the following arguments:<ul>
19389 * <li>r : Roo.data.Record[]</li>
19390 * <li>options: Options object from the load call</li>
19391 * <li>success: Boolean success indicator</li></ul></li>
19392 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19393 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19396 load : function(options){
19397 options = options || {};
19398 if(this.fireEvent("beforeload", this, options) !== false){
19399 this.storeOptions(options);
19400 var p = Roo.apply(options.params || {}, this.baseParams);
19401 // if meta was not loaded from remote source.. try requesting it.
19402 if (!this.reader.metaFromRemote) {
19403 p._requestMeta = 1;
19405 if(this.sortInfo && this.remoteSort){
19406 var pn = this.paramNames;
19407 p[pn["sort"]] = this.sortInfo.field;
19408 p[pn["dir"]] = this.sortInfo.direction;
19410 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19415 * Reloads the Record cache from the configured Proxy using the configured Reader and
19416 * the options from the last load operation performed.
19417 * @param {Object} options (optional) An object containing properties which may override the options
19418 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19419 * the most recently used options are reused).
19421 reload : function(options){
19422 this.load(Roo.applyIf(options||{}, this.lastOptions));
19426 // Called as a callback by the Reader during a load operation.
19427 loadRecords : function(o, options, success){
19428 if(!o || success === false){
19429 if(success !== false){
19430 this.fireEvent("load", this, [], options);
19432 if(options.callback){
19433 options.callback.call(options.scope || this, [], options, false);
19437 // if data returned failure - throw an exception.
19438 if (o.success === false) {
19439 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19442 var r = o.records, t = o.totalRecords || r.length;
19443 if(!options || options.add !== true){
19444 if(this.pruneModifiedRecords){
19445 this.modified = [];
19447 for(var i = 0, len = r.length; i < len; i++){
19451 this.data = this.snapshot;
19452 delete this.snapshot;
19455 this.data.addAll(r);
19456 this.totalLength = t;
19458 this.fireEvent("datachanged", this);
19460 this.totalLength = Math.max(t, this.data.length+r.length);
19463 this.fireEvent("load", this, r, options);
19464 if(options.callback){
19465 options.callback.call(options.scope || this, r, options, true);
19470 * Loads data from a passed data block. A Reader which understands the format of the data
19471 * must have been configured in the constructor.
19472 * @param {Object} data The data block from which to read the Records. The format of the data expected
19473 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19474 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19476 loadData : function(o, append){
19477 var r = this.reader.readRecords(o);
19478 this.loadRecords(r, {add: append}, true);
19482 * Gets the number of cached records.
19484 * <em>If using paging, this may not be the total size of the dataset. If the data object
19485 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19486 * the data set size</em>
19488 getCount : function(){
19489 return this.data.length || 0;
19493 * Gets the total number of records in the dataset as returned by the server.
19495 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19496 * the dataset size</em>
19498 getTotalCount : function(){
19499 return this.totalLength || 0;
19503 * Returns the sort state of the Store as an object with two properties:
19505 field {String} The name of the field by which the Records are sorted
19506 direction {String} The sort order, "ASC" or "DESC"
19509 getSortState : function(){
19510 return this.sortInfo;
19514 applySort : function(){
19515 if(this.sortInfo && !this.remoteSort){
19516 var s = this.sortInfo, f = s.field;
19517 var st = this.fields.get(f).sortType;
19518 var fn = function(r1, r2){
19519 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19520 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19522 this.data.sort(s.direction, fn);
19523 if(this.snapshot && this.snapshot != this.data){
19524 this.snapshot.sort(s.direction, fn);
19530 * Sets the default sort column and order to be used by the next load operation.
19531 * @param {String} fieldName The name of the field to sort by.
19532 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19534 setDefaultSort : function(field, dir){
19535 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19539 * Sort the Records.
19540 * If remote sorting is used, the sort is performed on the server, and the cache is
19541 * reloaded. If local sorting is used, the cache is sorted internally.
19542 * @param {String} fieldName The name of the field to sort by.
19543 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19545 sort : function(fieldName, dir){
19546 var f = this.fields.get(fieldName);
19548 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19549 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19554 this.sortToggle[f.name] = dir;
19555 this.sortInfo = {field: f.name, direction: dir};
19556 if(!this.remoteSort){
19558 this.fireEvent("datachanged", this);
19560 this.load(this.lastOptions);
19565 * Calls the specified function for each of the Records in the cache.
19566 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19567 * Returning <em>false</em> aborts and exits the iteration.
19568 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19570 each : function(fn, scope){
19571 this.data.each(fn, scope);
19575 * Gets all records modified since the last commit. Modified records are persisted across load operations
19576 * (e.g., during paging).
19577 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19579 getModifiedRecords : function(){
19580 return this.modified;
19584 createFilterFn : function(property, value, anyMatch){
19585 if(!value.exec){ // not a regex
19586 value = String(value);
19587 if(value.length == 0){
19590 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19592 return function(r){
19593 return value.test(r.data[property]);
19598 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19599 * @param {String} property A field on your records
19600 * @param {Number} start The record index to start at (defaults to 0)
19601 * @param {Number} end The last record index to include (defaults to length - 1)
19602 * @return {Number} The sum
19604 sum : function(property, start, end){
19605 var rs = this.data.items, v = 0;
19606 start = start || 0;
19607 end = (end || end === 0) ? end : rs.length-1;
19609 for(var i = start; i <= end; i++){
19610 v += (rs[i].data[property] || 0);
19616 * Filter the records by a specified property.
19617 * @param {String} field A field on your records
19618 * @param {String/RegExp} value Either a string that the field
19619 * should start with or a RegExp to test against the field
19620 * @param {Boolean} anyMatch True to match any part not just the beginning
19622 filter : function(property, value, anyMatch){
19623 var fn = this.createFilterFn(property, value, anyMatch);
19624 return fn ? this.filterBy(fn) : this.clearFilter();
19628 * Filter by a function. The specified function will be called with each
19629 * record in this data source. If the function returns true the record is included,
19630 * otherwise it is filtered.
19631 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19632 * @param {Object} scope (optional) The scope of the function (defaults to this)
19634 filterBy : function(fn, scope){
19635 this.snapshot = this.snapshot || this.data;
19636 this.data = this.queryBy(fn, scope||this);
19637 this.fireEvent("datachanged", this);
19641 * Query the records by a specified property.
19642 * @param {String} field A field on your records
19643 * @param {String/RegExp} value Either a string that the field
19644 * should start with or a RegExp to test against the field
19645 * @param {Boolean} anyMatch True to match any part not just the beginning
19646 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19648 query : function(property, value, anyMatch){
19649 var fn = this.createFilterFn(property, value, anyMatch);
19650 return fn ? this.queryBy(fn) : this.data.clone();
19654 * Query by a function. The specified function will be called with each
19655 * record in this data source. If the function returns true the record is included
19657 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19658 * @param {Object} scope (optional) The scope of the function (defaults to this)
19659 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19661 queryBy : function(fn, scope){
19662 var data = this.snapshot || this.data;
19663 return data.filterBy(fn, scope||this);
19667 * Collects unique values for a particular dataIndex from this store.
19668 * @param {String} dataIndex The property to collect
19669 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19670 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19671 * @return {Array} An array of the unique values
19673 collect : function(dataIndex, allowNull, bypassFilter){
19674 var d = (bypassFilter === true && this.snapshot) ?
19675 this.snapshot.items : this.data.items;
19676 var v, sv, r = [], l = {};
19677 for(var i = 0, len = d.length; i < len; i++){
19678 v = d[i].data[dataIndex];
19680 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19689 * Revert to a view of the Record cache with no filtering applied.
19690 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19692 clearFilter : function(suppressEvent){
19693 if(this.snapshot && this.snapshot != this.data){
19694 this.data = this.snapshot;
19695 delete this.snapshot;
19696 if(suppressEvent !== true){
19697 this.fireEvent("datachanged", this);
19703 afterEdit : function(record){
19704 if(this.modified.indexOf(record) == -1){
19705 this.modified.push(record);
19707 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19711 afterReject : function(record){
19712 this.modified.remove(record);
19713 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19717 afterCommit : function(record){
19718 this.modified.remove(record);
19719 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19723 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19724 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19726 commitChanges : function(){
19727 var m = this.modified.slice(0);
19728 this.modified = [];
19729 for(var i = 0, len = m.length; i < len; i++){
19735 * Cancel outstanding changes on all changed records.
19737 rejectChanges : function(){
19738 var m = this.modified.slice(0);
19739 this.modified = [];
19740 for(var i = 0, len = m.length; i < len; i++){
19745 onMetaChange : function(meta, rtype, o){
19746 this.recordType = rtype;
19747 this.fields = rtype.prototype.fields;
19748 delete this.snapshot;
19749 this.sortInfo = meta.sortInfo || this.sortInfo;
19750 this.modified = [];
19751 this.fireEvent('metachange', this, this.reader.meta);
19755 * Ext JS Library 1.1.1
19756 * Copyright(c) 2006-2007, Ext JS, LLC.
19758 * Originally Released Under LGPL - original licence link has changed is not relivant.
19761 * <script type="text/javascript">
19765 * @class Roo.data.SimpleStore
19766 * @extends Roo.data.Store
19767 * Small helper class to make creating Stores from Array data easier.
19768 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19769 * @cfg {Array} fields An array of field definition objects, or field name strings.
19770 * @cfg {Array} data The multi-dimensional array of data
19772 * @param {Object} config
19774 Roo.data.SimpleStore = function(config){
19775 Roo.data.SimpleStore.superclass.constructor.call(this, {
19777 reader: new Roo.data.ArrayReader({
19780 Roo.data.Record.create(config.fields)
19782 proxy : new Roo.data.MemoryProxy(config.data)
19786 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19788 * Ext JS Library 1.1.1
19789 * Copyright(c) 2006-2007, Ext JS, LLC.
19791 * Originally Released Under LGPL - original licence link has changed is not relivant.
19794 * <script type="text/javascript">
19799 * @extends Roo.data.Store
19800 * @class Roo.data.JsonStore
19801 * Small helper class to make creating Stores for JSON data easier. <br/>
19803 var store = new Roo.data.JsonStore({
19804 url: 'get-images.php',
19806 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19809 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19810 * JsonReader and HttpProxy (unless inline data is provided).</b>
19811 * @cfg {Array} fields An array of field definition objects, or field name strings.
19813 * @param {Object} config
19815 Roo.data.JsonStore = function(c){
19816 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19817 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19818 reader: new Roo.data.JsonReader(c, c.fields)
19821 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19823 * Ext JS Library 1.1.1
19824 * Copyright(c) 2006-2007, Ext JS, LLC.
19826 * Originally Released Under LGPL - original licence link has changed is not relivant.
19829 * <script type="text/javascript">
19833 Roo.data.Field = function(config){
19834 if(typeof config == "string"){
19835 config = {name: config};
19837 Roo.apply(this, config);
19840 this.type = "auto";
19843 var st = Roo.data.SortTypes;
19844 // named sortTypes are supported, here we look them up
19845 if(typeof this.sortType == "string"){
19846 this.sortType = st[this.sortType];
19849 // set default sortType for strings and dates
19850 if(!this.sortType){
19853 this.sortType = st.asUCString;
19856 this.sortType = st.asDate;
19859 this.sortType = st.none;
19864 var stripRe = /[\$,%]/g;
19866 // prebuilt conversion function for this field, instead of
19867 // switching every time we're reading a value
19869 var cv, dateFormat = this.dateFormat;
19874 cv = function(v){ return v; };
19877 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19881 return v !== undefined && v !== null && v !== '' ?
19882 parseInt(String(v).replace(stripRe, ""), 10) : '';
19887 return v !== undefined && v !== null && v !== '' ?
19888 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19893 cv = function(v){ return v === true || v === "true" || v == 1; };
19900 if(v instanceof Date){
19904 if(dateFormat == "timestamp"){
19905 return new Date(v*1000);
19907 return Date.parseDate(v, dateFormat);
19909 var parsed = Date.parse(v);
19910 return parsed ? new Date(parsed) : null;
19919 Roo.data.Field.prototype = {
19927 * Ext JS Library 1.1.1
19928 * Copyright(c) 2006-2007, Ext JS, LLC.
19930 * Originally Released Under LGPL - original licence link has changed is not relivant.
19933 * <script type="text/javascript">
19936 // Base class for reading structured data from a data source. This class is intended to be
19937 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19940 * @class Roo.data.DataReader
19941 * Base class for reading structured data from a data source. This class is intended to be
19942 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19945 Roo.data.DataReader = function(meta, recordType){
19949 this.recordType = recordType instanceof Array ?
19950 Roo.data.Record.create(recordType) : recordType;
19953 Roo.data.DataReader.prototype = {
19955 * Create an empty record
19956 * @param {Object} data (optional) - overlay some values
19957 * @return {Roo.data.Record} record created.
19959 newRow : function(d) {
19961 this.recordType.prototype.fields.each(function(c) {
19963 case 'int' : da[c.name] = 0; break;
19964 case 'date' : da[c.name] = new Date(); break;
19965 case 'float' : da[c.name] = 0.0; break;
19966 case 'boolean' : da[c.name] = false; break;
19967 default : da[c.name] = ""; break;
19971 return new this.recordType(Roo.apply(da, d));
19976 * Ext JS Library 1.1.1
19977 * Copyright(c) 2006-2007, Ext JS, LLC.
19979 * Originally Released Under LGPL - original licence link has changed is not relivant.
19982 * <script type="text/javascript">
19986 * @class Roo.data.DataProxy
19987 * @extends Roo.data.Observable
19988 * This class is an abstract base class for implementations which provide retrieval of
19989 * unformatted data objects.<br>
19991 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19992 * (of the appropriate type which knows how to parse the data object) to provide a block of
19993 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19995 * Custom implementations must implement the load method as described in
19996 * {@link Roo.data.HttpProxy#load}.
19998 Roo.data.DataProxy = function(){
20001 * @event beforeload
20002 * Fires before a network request is made to retrieve a data object.
20003 * @param {Object} This DataProxy object.
20004 * @param {Object} params The params parameter to the load function.
20009 * Fires before the load method's callback is called.
20010 * @param {Object} This DataProxy object.
20011 * @param {Object} o The data object.
20012 * @param {Object} arg The callback argument object passed to the load function.
20016 * @event loadexception
20017 * Fires if an Exception occurs during data retrieval.
20018 * @param {Object} This DataProxy object.
20019 * @param {Object} o The data object.
20020 * @param {Object} arg The callback argument object passed to the load function.
20021 * @param {Object} e The Exception.
20023 loadexception : true
20025 Roo.data.DataProxy.superclass.constructor.call(this);
20028 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20031 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20035 * Ext JS Library 1.1.1
20036 * Copyright(c) 2006-2007, Ext JS, LLC.
20038 * Originally Released Under LGPL - original licence link has changed is not relivant.
20041 * <script type="text/javascript">
20044 * @class Roo.data.MemoryProxy
20045 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20046 * to the Reader when its load method is called.
20048 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20050 Roo.data.MemoryProxy = function(data){
20054 Roo.data.MemoryProxy.superclass.constructor.call(this);
20058 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20060 * Load data from the requested source (in this case an in-memory
20061 * data object passed to the constructor), read the data object into
20062 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20063 * process that block using the passed callback.
20064 * @param {Object} params This parameter is not used by the MemoryProxy class.
20065 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20066 * object into a block of Roo.data.Records.
20067 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20068 * The function must be passed <ul>
20069 * <li>The Record block object</li>
20070 * <li>The "arg" argument from the load function</li>
20071 * <li>A boolean success indicator</li>
20073 * @param {Object} scope The scope in which to call the callback
20074 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20076 load : function(params, reader, callback, scope, arg){
20077 params = params || {};
20080 result = reader.readRecords(this.data);
20082 this.fireEvent("loadexception", this, arg, null, e);
20083 callback.call(scope, null, arg, false);
20086 callback.call(scope, result, arg, true);
20090 update : function(params, records){
20095 * Ext JS Library 1.1.1
20096 * Copyright(c) 2006-2007, Ext JS, LLC.
20098 * Originally Released Under LGPL - original licence link has changed is not relivant.
20101 * <script type="text/javascript">
20104 * @class Roo.data.HttpProxy
20105 * @extends Roo.data.DataProxy
20106 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20107 * configured to reference a certain URL.<br><br>
20109 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20110 * from which the running page was served.<br><br>
20112 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20114 * Be aware that to enable the browser to parse an XML document, the server must set
20115 * the Content-Type header in the HTTP response to "text/xml".
20117 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20118 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20119 * will be used to make the request.
20121 Roo.data.HttpProxy = function(conn){
20122 Roo.data.HttpProxy.superclass.constructor.call(this);
20123 // is conn a conn config or a real conn?
20125 this.useAjax = !conn || !conn.events;
20129 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20130 // thse are take from connection...
20133 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20136 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20137 * extra parameters to each request made by this object. (defaults to undefined)
20140 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20141 * to each request made by this object. (defaults to undefined)
20144 * @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)
20147 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20150 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20156 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20160 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20161 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20162 * a finer-grained basis than the DataProxy events.
20164 getConnection : function(){
20165 return this.useAjax ? Roo.Ajax : this.conn;
20169 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20170 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20171 * process that block using the passed callback.
20172 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20173 * for the request to the remote server.
20174 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20175 * object into a block of Roo.data.Records.
20176 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20177 * The function must be passed <ul>
20178 * <li>The Record block object</li>
20179 * <li>The "arg" argument from the load function</li>
20180 * <li>A boolean success indicator</li>
20182 * @param {Object} scope The scope in which to call the callback
20183 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20185 load : function(params, reader, callback, scope, arg){
20186 if(this.fireEvent("beforeload", this, params) !== false){
20188 params : params || {},
20190 callback : callback,
20195 callback : this.loadResponse,
20199 Roo.applyIf(o, this.conn);
20200 if(this.activeRequest){
20201 Roo.Ajax.abort(this.activeRequest);
20203 this.activeRequest = Roo.Ajax.request(o);
20205 this.conn.request(o);
20208 callback.call(scope||this, null, arg, false);
20213 loadResponse : function(o, success, response){
20214 delete this.activeRequest;
20216 this.fireEvent("loadexception", this, o, response);
20217 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20222 result = o.reader.read(response);
20224 this.fireEvent("loadexception", this, o, response, e);
20225 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20229 this.fireEvent("load", this, o, o.request.arg);
20230 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20234 update : function(dataSet){
20239 updateResponse : function(dataSet){
20244 * Ext JS Library 1.1.1
20245 * Copyright(c) 2006-2007, Ext JS, LLC.
20247 * Originally Released Under LGPL - original licence link has changed is not relivant.
20250 * <script type="text/javascript">
20254 * @class Roo.data.ScriptTagProxy
20255 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20256 * other than the originating domain of the running page.<br><br>
20258 * <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
20259 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20261 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20262 * source code that is used as the source inside a <script> tag.<br><br>
20264 * In order for the browser to process the returned data, the server must wrap the data object
20265 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20266 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20267 * depending on whether the callback name was passed:
20270 boolean scriptTag = false;
20271 String cb = request.getParameter("callback");
20274 response.setContentType("text/javascript");
20276 response.setContentType("application/x-json");
20278 Writer out = response.getWriter();
20280 out.write(cb + "(");
20282 out.print(dataBlock.toJsonString());
20289 * @param {Object} config A configuration object.
20291 Roo.data.ScriptTagProxy = function(config){
20292 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20293 Roo.apply(this, config);
20294 this.head = document.getElementsByTagName("head")[0];
20297 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20299 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20301 * @cfg {String} url The URL from which to request the data object.
20304 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20308 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20309 * the server the name of the callback function set up by the load call to process the returned data object.
20310 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20311 * javascript output which calls this named function passing the data object as its only parameter.
20313 callbackParam : "callback",
20315 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20316 * name to the request.
20321 * Load data from the configured URL, read the data object into
20322 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20323 * process that block using the passed callback.
20324 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20325 * for the request to the remote server.
20326 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20327 * object into a block of Roo.data.Records.
20328 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20329 * The function must be passed <ul>
20330 * <li>The Record block object</li>
20331 * <li>The "arg" argument from the load function</li>
20332 * <li>A boolean success indicator</li>
20334 * @param {Object} scope The scope in which to call the callback
20335 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20337 load : function(params, reader, callback, scope, arg){
20338 if(this.fireEvent("beforeload", this, params) !== false){
20340 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20342 var url = this.url;
20343 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20345 url += "&_dc=" + (new Date().getTime());
20347 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20350 cb : "stcCallback"+transId,
20351 scriptId : "stcScript"+transId,
20355 callback : callback,
20361 window[trans.cb] = function(o){
20362 conn.handleResponse(o, trans);
20365 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20367 if(this.autoAbort !== false){
20371 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20373 var script = document.createElement("script");
20374 script.setAttribute("src", url);
20375 script.setAttribute("type", "text/javascript");
20376 script.setAttribute("id", trans.scriptId);
20377 this.head.appendChild(script);
20379 this.trans = trans;
20381 callback.call(scope||this, null, arg, false);
20386 isLoading : function(){
20387 return this.trans ? true : false;
20391 * Abort the current server request.
20393 abort : function(){
20394 if(this.isLoading()){
20395 this.destroyTrans(this.trans);
20400 destroyTrans : function(trans, isLoaded){
20401 this.head.removeChild(document.getElementById(trans.scriptId));
20402 clearTimeout(trans.timeoutId);
20404 window[trans.cb] = undefined;
20406 delete window[trans.cb];
20409 // if hasn't been loaded, wait for load to remove it to prevent script error
20410 window[trans.cb] = function(){
20411 window[trans.cb] = undefined;
20413 delete window[trans.cb];
20420 handleResponse : function(o, trans){
20421 this.trans = false;
20422 this.destroyTrans(trans, true);
20425 result = trans.reader.readRecords(o);
20427 this.fireEvent("loadexception", this, o, trans.arg, e);
20428 trans.callback.call(trans.scope||window, null, trans.arg, false);
20431 this.fireEvent("load", this, o, trans.arg);
20432 trans.callback.call(trans.scope||window, result, trans.arg, true);
20436 handleFailure : function(trans){
20437 this.trans = false;
20438 this.destroyTrans(trans, false);
20439 this.fireEvent("loadexception", this, null, trans.arg);
20440 trans.callback.call(trans.scope||window, null, trans.arg, false);
20444 * Ext JS Library 1.1.1
20445 * Copyright(c) 2006-2007, Ext JS, LLC.
20447 * Originally Released Under LGPL - original licence link has changed is not relivant.
20450 * <script type="text/javascript">
20454 * @class Roo.data.JsonReader
20455 * @extends Roo.data.DataReader
20456 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20457 * based on mappings in a provided Roo.data.Record constructor.
20459 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20460 * in the reply previously.
20465 var RecordDef = Roo.data.Record.create([
20466 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20467 {name: 'occupation'} // This field will use "occupation" as the mapping.
20469 var myReader = new Roo.data.JsonReader({
20470 totalProperty: "results", // The property which contains the total dataset size (optional)
20471 root: "rows", // The property which contains an Array of row objects
20472 id: "id" // The property within each row object that provides an ID for the record (optional)
20476 * This would consume a JSON file like this:
20478 { 'results': 2, 'rows': [
20479 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20480 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20483 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20484 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20485 * paged from the remote server.
20486 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20487 * @cfg {String} root name of the property which contains the Array of row objects.
20488 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20490 * Create a new JsonReader
20491 * @param {Object} meta Metadata configuration options
20492 * @param {Object} recordType Either an Array of field definition objects,
20493 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20495 Roo.data.JsonReader = function(meta, recordType){
20498 // set some defaults:
20499 Roo.applyIf(meta, {
20500 totalProperty: 'total',
20501 successProperty : 'success',
20506 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20508 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20511 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20512 * Used by Store query builder to append _requestMeta to params.
20515 metaFromRemote : false,
20517 * This method is only used by a DataProxy which has retrieved data from a remote server.
20518 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20519 * @return {Object} data A data block which is used by an Roo.data.Store object as
20520 * a cache of Roo.data.Records.
20522 read : function(response){
20523 var json = response.responseText;
20525 var o = /* eval:var:o */ eval("("+json+")");
20527 throw {message: "JsonReader.read: Json object not found"};
20533 this.metaFromRemote = true;
20534 this.meta = o.metaData;
20535 this.recordType = Roo.data.Record.create(o.metaData.fields);
20536 this.onMetaChange(this.meta, this.recordType, o);
20538 return this.readRecords(o);
20541 // private function a store will implement
20542 onMetaChange : function(meta, recordType, o){
20549 simpleAccess: function(obj, subsc) {
20556 getJsonAccessor: function(){
20558 return function(expr) {
20560 return(re.test(expr))
20561 ? new Function("obj", "return obj." + expr)
20566 return Roo.emptyFn;
20571 * Create a data block containing Roo.data.Records from an XML document.
20572 * @param {Object} o An object which contains an Array of row objects in the property specified
20573 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20574 * which contains the total size of the dataset.
20575 * @return {Object} data A data block which is used by an Roo.data.Store object as
20576 * a cache of Roo.data.Records.
20578 readRecords : function(o){
20580 * After any data loads, the raw JSON data is available for further custom processing.
20584 var s = this.meta, Record = this.recordType,
20585 f = Record.prototype.fields, fi = f.items, fl = f.length;
20587 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20589 if(s.totalProperty) {
20590 this.getTotal = this.getJsonAccessor(s.totalProperty);
20592 if(s.successProperty) {
20593 this.getSuccess = this.getJsonAccessor(s.successProperty);
20595 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20597 var g = this.getJsonAccessor(s.id);
20598 this.getId = function(rec) {
20600 return (r === undefined || r === "") ? null : r;
20603 this.getId = function(){return null;};
20606 for(var jj = 0; jj < fl; jj++){
20608 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20609 this.ef[jj] = this.getJsonAccessor(map);
20613 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20614 if(s.totalProperty){
20615 var vt = parseInt(this.getTotal(o), 10);
20620 if(s.successProperty){
20621 var vs = this.getSuccess(o);
20622 if(vs === false || vs === 'false'){
20627 for(var i = 0; i < c; i++){
20630 var id = this.getId(n);
20631 for(var j = 0; j < fl; j++){
20633 var v = this.ef[j](n);
20635 Roo.log('missing convert for ' + f.name);
20639 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20641 var record = new Record(values, id);
20643 records[i] = record;
20648 totalRecords : totalRecords
20653 * Ext JS Library 1.1.1
20654 * Copyright(c) 2006-2007, Ext JS, LLC.
20656 * Originally Released Under LGPL - original licence link has changed is not relivant.
20659 * <script type="text/javascript">
20663 * @class Roo.data.XmlReader
20664 * @extends Roo.data.DataReader
20665 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20666 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20668 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20669 * header in the HTTP response must be set to "text/xml".</em>
20673 var RecordDef = Roo.data.Record.create([
20674 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20675 {name: 'occupation'} // This field will use "occupation" as the mapping.
20677 var myReader = new Roo.data.XmlReader({
20678 totalRecords: "results", // The element which contains the total dataset size (optional)
20679 record: "row", // The repeated element which contains row information
20680 id: "id" // The element within the row that provides an ID for the record (optional)
20684 * This would consume an XML file like this:
20688 <results>2</results>
20691 <name>Bill</name>
20692 <occupation>Gardener</occupation>
20696 <name>Ben</name>
20697 <occupation>Horticulturalist</occupation>
20701 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20702 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20703 * paged from the remote server.
20704 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20705 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20706 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20707 * a record identifier value.
20709 * Create a new XmlReader
20710 * @param {Object} meta Metadata configuration options
20711 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20712 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20713 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20715 Roo.data.XmlReader = function(meta, recordType){
20717 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20719 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20721 * This method is only used by a DataProxy which has retrieved data from a remote server.
20722 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20723 * to contain a method called 'responseXML' that returns an XML document object.
20724 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20725 * a cache of Roo.data.Records.
20727 read : function(response){
20728 var doc = response.responseXML;
20730 throw {message: "XmlReader.read: XML Document not available"};
20732 return this.readRecords(doc);
20736 * Create a data block containing Roo.data.Records from an XML document.
20737 * @param {Object} doc A parsed XML document.
20738 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20739 * a cache of Roo.data.Records.
20741 readRecords : function(doc){
20743 * After any data loads/reads, the raw XML Document is available for further custom processing.
20744 * @type XMLDocument
20746 this.xmlData = doc;
20747 var root = doc.documentElement || doc;
20748 var q = Roo.DomQuery;
20749 var recordType = this.recordType, fields = recordType.prototype.fields;
20750 var sid = this.meta.id;
20751 var totalRecords = 0, success = true;
20752 if(this.meta.totalRecords){
20753 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20756 if(this.meta.success){
20757 var sv = q.selectValue(this.meta.success, root, true);
20758 success = sv !== false && sv !== 'false';
20761 var ns = q.select(this.meta.record, root);
20762 for(var i = 0, len = ns.length; i < len; i++) {
20765 var id = sid ? q.selectValue(sid, n) : undefined;
20766 for(var j = 0, jlen = fields.length; j < jlen; j++){
20767 var f = fields.items[j];
20768 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20770 values[f.name] = v;
20772 var record = new recordType(values, id);
20774 records[records.length] = record;
20780 totalRecords : totalRecords || records.length
20785 * Ext JS Library 1.1.1
20786 * Copyright(c) 2006-2007, Ext JS, LLC.
20788 * Originally Released Under LGPL - original licence link has changed is not relivant.
20791 * <script type="text/javascript">
20795 * @class Roo.data.ArrayReader
20796 * @extends Roo.data.DataReader
20797 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20798 * Each element of that Array represents a row of data fields. The
20799 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20800 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20804 var RecordDef = Roo.data.Record.create([
20805 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20806 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20808 var myReader = new Roo.data.ArrayReader({
20809 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20813 * This would consume an Array like this:
20815 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20817 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20819 * Create a new JsonReader
20820 * @param {Object} meta Metadata configuration options.
20821 * @param {Object} recordType Either an Array of field definition objects
20822 * as specified to {@link Roo.data.Record#create},
20823 * or an {@link Roo.data.Record} object
20824 * created using {@link Roo.data.Record#create}.
20826 Roo.data.ArrayReader = function(meta, recordType){
20827 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20830 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20832 * Create a data block containing Roo.data.Records from an XML document.
20833 * @param {Object} o An Array of row objects which represents the dataset.
20834 * @return {Object} data A data block which is used by an Roo.data.Store object as
20835 * a cache of Roo.data.Records.
20837 readRecords : function(o){
20838 var sid = this.meta ? this.meta.id : null;
20839 var recordType = this.recordType, fields = recordType.prototype.fields;
20842 for(var i = 0; i < root.length; i++){
20845 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20846 for(var j = 0, jlen = fields.length; j < jlen; j++){
20847 var f = fields.items[j];
20848 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20849 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20851 values[f.name] = v;
20853 var record = new recordType(values, id);
20855 records[records.length] = record;
20859 totalRecords : records.length
20864 * Ext JS Library 1.1.1
20865 * Copyright(c) 2006-2007, Ext JS, LLC.
20867 * Originally Released Under LGPL - original licence link has changed is not relivant.
20870 * <script type="text/javascript">
20875 * @class Roo.data.Tree
20876 * @extends Roo.util.Observable
20877 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20878 * in the tree have most standard DOM functionality.
20880 * @param {Node} root (optional) The root node
20882 Roo.data.Tree = function(root){
20883 this.nodeHash = {};
20885 * The root node for this tree
20890 this.setRootNode(root);
20895 * Fires when a new child node is appended to a node in this tree.
20896 * @param {Tree} tree The owner tree
20897 * @param {Node} parent The parent node
20898 * @param {Node} node The newly appended node
20899 * @param {Number} index The index of the newly appended node
20904 * Fires when a child node is removed from a node in this tree.
20905 * @param {Tree} tree The owner tree
20906 * @param {Node} parent The parent node
20907 * @param {Node} node The child node removed
20912 * Fires when a node is moved to a new location in the tree
20913 * @param {Tree} tree The owner tree
20914 * @param {Node} node The node moved
20915 * @param {Node} oldParent The old parent of this node
20916 * @param {Node} newParent The new parent of this node
20917 * @param {Number} index The index it was moved to
20922 * Fires when a new child node is inserted in a node in this tree.
20923 * @param {Tree} tree The owner tree
20924 * @param {Node} parent The parent node
20925 * @param {Node} node The child node inserted
20926 * @param {Node} refNode The child node the node was inserted before
20930 * @event beforeappend
20931 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20932 * @param {Tree} tree The owner tree
20933 * @param {Node} parent The parent node
20934 * @param {Node} node The child node to be appended
20936 "beforeappend" : true,
20938 * @event beforeremove
20939 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20940 * @param {Tree} tree The owner tree
20941 * @param {Node} parent The parent node
20942 * @param {Node} node The child node to be removed
20944 "beforeremove" : true,
20946 * @event beforemove
20947 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20948 * @param {Tree} tree The owner tree
20949 * @param {Node} node The node being moved
20950 * @param {Node} oldParent The parent of the node
20951 * @param {Node} newParent The new parent the node is moving to
20952 * @param {Number} index The index it is being moved to
20954 "beforemove" : true,
20956 * @event beforeinsert
20957 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20958 * @param {Tree} tree The owner tree
20959 * @param {Node} parent The parent node
20960 * @param {Node} node The child node to be inserted
20961 * @param {Node} refNode The child node the node is being inserted before
20963 "beforeinsert" : true
20966 Roo.data.Tree.superclass.constructor.call(this);
20969 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20970 pathSeparator: "/",
20972 proxyNodeEvent : function(){
20973 return this.fireEvent.apply(this, arguments);
20977 * Returns the root node for this tree.
20980 getRootNode : function(){
20985 * Sets the root node for this tree.
20986 * @param {Node} node
20989 setRootNode : function(node){
20991 node.ownerTree = this;
20992 node.isRoot = true;
20993 this.registerNode(node);
20998 * Gets a node in this tree by its id.
20999 * @param {String} id
21002 getNodeById : function(id){
21003 return this.nodeHash[id];
21006 registerNode : function(node){
21007 this.nodeHash[node.id] = node;
21010 unregisterNode : function(node){
21011 delete this.nodeHash[node.id];
21014 toString : function(){
21015 return "[Tree"+(this.id?" "+this.id:"")+"]";
21020 * @class Roo.data.Node
21021 * @extends Roo.util.Observable
21022 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21023 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21025 * @param {Object} attributes The attributes/config for the node
21027 Roo.data.Node = function(attributes){
21029 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21032 this.attributes = attributes || {};
21033 this.leaf = this.attributes.leaf;
21035 * The node id. @type String
21037 this.id = this.attributes.id;
21039 this.id = Roo.id(null, "ynode-");
21040 this.attributes.id = this.id;
21043 * All child nodes of this node. @type Array
21045 this.childNodes = [];
21046 if(!this.childNodes.indexOf){ // indexOf is a must
21047 this.childNodes.indexOf = function(o){
21048 for(var i = 0, len = this.length; i < len; i++){
21057 * The parent node for this node. @type Node
21059 this.parentNode = null;
21061 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21063 this.firstChild = null;
21065 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21067 this.lastChild = null;
21069 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21071 this.previousSibling = null;
21073 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21075 this.nextSibling = null;
21080 * Fires when a new child node is appended
21081 * @param {Tree} tree The owner tree
21082 * @param {Node} this This node
21083 * @param {Node} node The newly appended node
21084 * @param {Number} index The index of the newly appended node
21089 * Fires when a child node is removed
21090 * @param {Tree} tree The owner tree
21091 * @param {Node} this This node
21092 * @param {Node} node The removed node
21097 * Fires when this node is moved to a new location in the tree
21098 * @param {Tree} tree The owner tree
21099 * @param {Node} this This node
21100 * @param {Node} oldParent The old parent of this node
21101 * @param {Node} newParent The new parent of this node
21102 * @param {Number} index The index it was moved to
21107 * Fires when a new child node is inserted.
21108 * @param {Tree} tree The owner tree
21109 * @param {Node} this This node
21110 * @param {Node} node The child node inserted
21111 * @param {Node} refNode The child node the node was inserted before
21115 * @event beforeappend
21116 * Fires before a new child is appended, return false to cancel the append.
21117 * @param {Tree} tree The owner tree
21118 * @param {Node} this This node
21119 * @param {Node} node The child node to be appended
21121 "beforeappend" : true,
21123 * @event beforeremove
21124 * Fires before a child is removed, return false to cancel the remove.
21125 * @param {Tree} tree The owner tree
21126 * @param {Node} this This node
21127 * @param {Node} node The child node to be removed
21129 "beforeremove" : true,
21131 * @event beforemove
21132 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21133 * @param {Tree} tree The owner tree
21134 * @param {Node} this This node
21135 * @param {Node} oldParent The parent of this node
21136 * @param {Node} newParent The new parent this node is moving to
21137 * @param {Number} index The index it is being moved to
21139 "beforemove" : true,
21141 * @event beforeinsert
21142 * Fires before a new child is inserted, return false to cancel the insert.
21143 * @param {Tree} tree The owner tree
21144 * @param {Node} this This node
21145 * @param {Node} node The child node to be inserted
21146 * @param {Node} refNode The child node the node is being inserted before
21148 "beforeinsert" : true
21150 this.listeners = this.attributes.listeners;
21151 Roo.data.Node.superclass.constructor.call(this);
21154 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21155 fireEvent : function(evtName){
21156 // first do standard event for this node
21157 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21160 // then bubble it up to the tree if the event wasn't cancelled
21161 var ot = this.getOwnerTree();
21163 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21171 * Returns true if this node is a leaf
21172 * @return {Boolean}
21174 isLeaf : function(){
21175 return this.leaf === true;
21179 setFirstChild : function(node){
21180 this.firstChild = node;
21184 setLastChild : function(node){
21185 this.lastChild = node;
21190 * Returns true if this node is the last child of its parent
21191 * @return {Boolean}
21193 isLast : function(){
21194 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21198 * Returns true if this node is the first child of its parent
21199 * @return {Boolean}
21201 isFirst : function(){
21202 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21205 hasChildNodes : function(){
21206 return !this.isLeaf() && this.childNodes.length > 0;
21210 * Insert node(s) as the last child node of this node.
21211 * @param {Node/Array} node The node or Array of nodes to append
21212 * @return {Node} The appended node if single append, or null if an array was passed
21214 appendChild : function(node){
21216 if(node instanceof Array){
21218 }else if(arguments.length > 1){
21221 // if passed an array or multiple args do them one by one
21223 for(var i = 0, len = multi.length; i < len; i++) {
21224 this.appendChild(multi[i]);
21227 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21230 var index = this.childNodes.length;
21231 var oldParent = node.parentNode;
21232 // it's a move, make sure we move it cleanly
21234 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21237 oldParent.removeChild(node);
21239 index = this.childNodes.length;
21241 this.setFirstChild(node);
21243 this.childNodes.push(node);
21244 node.parentNode = this;
21245 var ps = this.childNodes[index-1];
21247 node.previousSibling = ps;
21248 ps.nextSibling = node;
21250 node.previousSibling = null;
21252 node.nextSibling = null;
21253 this.setLastChild(node);
21254 node.setOwnerTree(this.getOwnerTree());
21255 this.fireEvent("append", this.ownerTree, this, node, index);
21257 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21264 * Removes a child node from this node.
21265 * @param {Node} node The node to remove
21266 * @return {Node} The removed node
21268 removeChild : function(node){
21269 var index = this.childNodes.indexOf(node);
21273 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21277 // remove it from childNodes collection
21278 this.childNodes.splice(index, 1);
21281 if(node.previousSibling){
21282 node.previousSibling.nextSibling = node.nextSibling;
21284 if(node.nextSibling){
21285 node.nextSibling.previousSibling = node.previousSibling;
21288 // update child refs
21289 if(this.firstChild == node){
21290 this.setFirstChild(node.nextSibling);
21292 if(this.lastChild == node){
21293 this.setLastChild(node.previousSibling);
21296 node.setOwnerTree(null);
21297 // clear any references from the node
21298 node.parentNode = null;
21299 node.previousSibling = null;
21300 node.nextSibling = null;
21301 this.fireEvent("remove", this.ownerTree, this, node);
21306 * Inserts the first node before the second node in this nodes childNodes collection.
21307 * @param {Node} node The node to insert
21308 * @param {Node} refNode The node to insert before (if null the node is appended)
21309 * @return {Node} The inserted node
21311 insertBefore : function(node, refNode){
21312 if(!refNode){ // like standard Dom, refNode can be null for append
21313 return this.appendChild(node);
21316 if(node == refNode){
21320 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21323 var index = this.childNodes.indexOf(refNode);
21324 var oldParent = node.parentNode;
21325 var refIndex = index;
21327 // when moving internally, indexes will change after remove
21328 if(oldParent == this && this.childNodes.indexOf(node) < index){
21332 // it's a move, make sure we move it cleanly
21334 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21337 oldParent.removeChild(node);
21340 this.setFirstChild(node);
21342 this.childNodes.splice(refIndex, 0, node);
21343 node.parentNode = this;
21344 var ps = this.childNodes[refIndex-1];
21346 node.previousSibling = ps;
21347 ps.nextSibling = node;
21349 node.previousSibling = null;
21351 node.nextSibling = refNode;
21352 refNode.previousSibling = node;
21353 node.setOwnerTree(this.getOwnerTree());
21354 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21356 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21362 * Returns the child node at the specified index.
21363 * @param {Number} index
21366 item : function(index){
21367 return this.childNodes[index];
21371 * Replaces one child node in this node with another.
21372 * @param {Node} newChild The replacement node
21373 * @param {Node} oldChild The node to replace
21374 * @return {Node} The replaced node
21376 replaceChild : function(newChild, oldChild){
21377 this.insertBefore(newChild, oldChild);
21378 this.removeChild(oldChild);
21383 * Returns the index of a child node
21384 * @param {Node} node
21385 * @return {Number} The index of the node or -1 if it was not found
21387 indexOf : function(child){
21388 return this.childNodes.indexOf(child);
21392 * Returns the tree this node is in.
21395 getOwnerTree : function(){
21396 // if it doesn't have one, look for one
21397 if(!this.ownerTree){
21401 this.ownerTree = p.ownerTree;
21407 return this.ownerTree;
21411 * Returns depth of this node (the root node has a depth of 0)
21414 getDepth : function(){
21417 while(p.parentNode){
21425 setOwnerTree : function(tree){
21426 // if it's move, we need to update everyone
21427 if(tree != this.ownerTree){
21428 if(this.ownerTree){
21429 this.ownerTree.unregisterNode(this);
21431 this.ownerTree = tree;
21432 var cs = this.childNodes;
21433 for(var i = 0, len = cs.length; i < len; i++) {
21434 cs[i].setOwnerTree(tree);
21437 tree.registerNode(this);
21443 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21444 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21445 * @return {String} The path
21447 getPath : function(attr){
21448 attr = attr || "id";
21449 var p = this.parentNode;
21450 var b = [this.attributes[attr]];
21452 b.unshift(p.attributes[attr]);
21455 var sep = this.getOwnerTree().pathSeparator;
21456 return sep + b.join(sep);
21460 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21461 * function call will be the scope provided or the current node. The arguments to the function
21462 * will be the args provided or the current node. If the function returns false at any point,
21463 * the bubble is stopped.
21464 * @param {Function} fn The function to call
21465 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21466 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21468 bubble : function(fn, scope, args){
21471 if(fn.call(scope || p, args || p) === false){
21479 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21480 * function call will be the scope provided or the current node. The arguments to the function
21481 * will be the args provided or the current node. If the function returns false at any point,
21482 * the cascade is stopped on that branch.
21483 * @param {Function} fn The function to call
21484 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21485 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21487 cascade : function(fn, scope, args){
21488 if(fn.call(scope || this, args || this) !== false){
21489 var cs = this.childNodes;
21490 for(var i = 0, len = cs.length; i < len; i++) {
21491 cs[i].cascade(fn, scope, args);
21497 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21498 * function call will be the scope provided or the current node. The arguments to the function
21499 * will be the args provided or the current node. If the function returns false at any point,
21500 * the iteration stops.
21501 * @param {Function} fn The function to call
21502 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21503 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21505 eachChild : function(fn, scope, args){
21506 var cs = this.childNodes;
21507 for(var i = 0, len = cs.length; i < len; i++) {
21508 if(fn.call(scope || this, args || cs[i]) === false){
21515 * Finds the first child that has the attribute with the specified value.
21516 * @param {String} attribute The attribute name
21517 * @param {Mixed} value The value to search for
21518 * @return {Node} The found child or null if none was found
21520 findChild : function(attribute, value){
21521 var cs = this.childNodes;
21522 for(var i = 0, len = cs.length; i < len; i++) {
21523 if(cs[i].attributes[attribute] == value){
21531 * Finds the first child by a custom function. The child matches if the function passed
21533 * @param {Function} fn
21534 * @param {Object} scope (optional)
21535 * @return {Node} The found child or null if none was found
21537 findChildBy : function(fn, scope){
21538 var cs = this.childNodes;
21539 for(var i = 0, len = cs.length; i < len; i++) {
21540 if(fn.call(scope||cs[i], cs[i]) === true){
21548 * Sorts this nodes children using the supplied sort function
21549 * @param {Function} fn
21550 * @param {Object} scope (optional)
21552 sort : function(fn, scope){
21553 var cs = this.childNodes;
21554 var len = cs.length;
21556 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21558 for(var i = 0; i < len; i++){
21560 n.previousSibling = cs[i-1];
21561 n.nextSibling = cs[i+1];
21563 this.setFirstChild(n);
21566 this.setLastChild(n);
21573 * Returns true if this node is an ancestor (at any point) of the passed node.
21574 * @param {Node} node
21575 * @return {Boolean}
21577 contains : function(node){
21578 return node.isAncestor(this);
21582 * Returns true if the passed node is an ancestor (at any point) of this node.
21583 * @param {Node} node
21584 * @return {Boolean}
21586 isAncestor : function(node){
21587 var p = this.parentNode;
21597 toString : function(){
21598 return "[Node"+(this.id?" "+this.id:"")+"]";
21602 * Ext JS Library 1.1.1
21603 * Copyright(c) 2006-2007, Ext JS, LLC.
21605 * Originally Released Under LGPL - original licence link has changed is not relivant.
21608 * <script type="text/javascript">
21613 * @class Roo.ComponentMgr
21614 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21617 Roo.ComponentMgr = function(){
21618 var all = new Roo.util.MixedCollection();
21622 * Registers a component.
21623 * @param {Roo.Component} c The component
21625 register : function(c){
21630 * Unregisters a component.
21631 * @param {Roo.Component} c The component
21633 unregister : function(c){
21638 * Returns a component by id
21639 * @param {String} id The component id
21641 get : function(id){
21642 return all.get(id);
21646 * Registers a function that will be called when a specified component is added to ComponentMgr
21647 * @param {String} id The component id
21648 * @param {Funtction} fn The callback function
21649 * @param {Object} scope The scope of the callback
21651 onAvailable : function(id, fn, scope){
21652 all.on("add", function(index, o){
21654 fn.call(scope || o, o);
21655 all.un("add", fn, scope);
21662 * Ext JS Library 1.1.1
21663 * Copyright(c) 2006-2007, Ext JS, LLC.
21665 * Originally Released Under LGPL - original licence link has changed is not relivant.
21668 * <script type="text/javascript">
21672 * @class Roo.Component
21673 * @extends Roo.util.Observable
21674 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21675 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21676 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21677 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21678 * All visual components (widgets) that require rendering into a layout should subclass Component.
21680 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21681 * 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
21682 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21684 Roo.Component = function(config){
21685 config = config || {};
21686 if(config.tagName || config.dom || typeof config == "string"){ // element object
21687 config = {el: config, id: config.id || config};
21689 this.initialConfig = config;
21691 Roo.apply(this, config);
21695 * Fires after the component is disabled.
21696 * @param {Roo.Component} this
21701 * Fires after the component is enabled.
21702 * @param {Roo.Component} this
21706 * @event beforeshow
21707 * Fires before the component is shown. Return false to stop the show.
21708 * @param {Roo.Component} this
21713 * Fires after the component is shown.
21714 * @param {Roo.Component} this
21718 * @event beforehide
21719 * Fires before the component is hidden. Return false to stop the hide.
21720 * @param {Roo.Component} this
21725 * Fires after the component is hidden.
21726 * @param {Roo.Component} this
21730 * @event beforerender
21731 * Fires before the component is rendered. Return false to stop the render.
21732 * @param {Roo.Component} this
21734 beforerender : true,
21737 * Fires after the component is rendered.
21738 * @param {Roo.Component} this
21742 * @event beforedestroy
21743 * Fires before the component is destroyed. Return false to stop the destroy.
21744 * @param {Roo.Component} this
21746 beforedestroy : true,
21749 * Fires after the component is destroyed.
21750 * @param {Roo.Component} this
21755 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21757 Roo.ComponentMgr.register(this);
21758 Roo.Component.superclass.constructor.call(this);
21759 this.initComponent();
21760 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21761 this.render(this.renderTo);
21762 delete this.renderTo;
21767 Roo.Component.AUTO_ID = 1000;
21769 Roo.extend(Roo.Component, Roo.util.Observable, {
21771 * @property {Boolean} hidden
21772 * true if this component is hidden. Read-only.
21776 * true if this component is disabled. Read-only.
21780 * true if this component has been rendered. Read-only.
21784 /** @cfg {String} disableClass
21785 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21787 disabledClass : "x-item-disabled",
21788 /** @cfg {Boolean} allowDomMove
21789 * Whether the component can move the Dom node when rendering (defaults to true).
21791 allowDomMove : true,
21792 /** @cfg {String} hideMode
21793 * How this component should hidden. Supported values are
21794 * "visibility" (css visibility), "offsets" (negative offset position) and
21795 * "display" (css display) - defaults to "display".
21797 hideMode: 'display',
21800 ctype : "Roo.Component",
21802 /** @cfg {String} actionMode
21803 * which property holds the element that used for hide() / show() / disable() / enable()
21809 getActionEl : function(){
21810 return this[this.actionMode];
21813 initComponent : Roo.emptyFn,
21815 * If this is a lazy rendering component, render it to its container element.
21816 * @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.
21818 render : function(container, position){
21819 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21820 if(!container && this.el){
21821 this.el = Roo.get(this.el);
21822 container = this.el.dom.parentNode;
21823 this.allowDomMove = false;
21825 this.container = Roo.get(container);
21826 this.rendered = true;
21827 if(position !== undefined){
21828 if(typeof position == 'number'){
21829 position = this.container.dom.childNodes[position];
21831 position = Roo.getDom(position);
21834 this.onRender(this.container, position || null);
21836 this.el.addClass(this.cls);
21840 this.el.applyStyles(this.style);
21843 this.fireEvent("render", this);
21844 this.afterRender(this.container);
21856 // default function is not really useful
21857 onRender : function(ct, position){
21859 this.el = Roo.get(this.el);
21860 if(this.allowDomMove !== false){
21861 ct.dom.insertBefore(this.el.dom, position);
21867 getAutoCreate : function(){
21868 var cfg = typeof this.autoCreate == "object" ?
21869 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21870 if(this.id && !cfg.id){
21877 afterRender : Roo.emptyFn,
21880 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21881 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21883 destroy : function(){
21884 if(this.fireEvent("beforedestroy", this) !== false){
21885 this.purgeListeners();
21886 this.beforeDestroy();
21888 this.el.removeAllListeners();
21890 if(this.actionMode == "container"){
21891 this.container.remove();
21895 Roo.ComponentMgr.unregister(this);
21896 this.fireEvent("destroy", this);
21901 beforeDestroy : function(){
21906 onDestroy : function(){
21911 * Returns the underlying {@link Roo.Element}.
21912 * @return {Roo.Element} The element
21914 getEl : function(){
21919 * Returns the id of this component.
21922 getId : function(){
21927 * Try to focus this component.
21928 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21929 * @return {Roo.Component} this
21931 focus : function(selectText){
21934 if(selectText === true){
21935 this.el.dom.select();
21950 * Disable this component.
21951 * @return {Roo.Component} this
21953 disable : function(){
21957 this.disabled = true;
21958 this.fireEvent("disable", this);
21963 onDisable : function(){
21964 this.getActionEl().addClass(this.disabledClass);
21965 this.el.dom.disabled = true;
21969 * Enable this component.
21970 * @return {Roo.Component} this
21972 enable : function(){
21976 this.disabled = false;
21977 this.fireEvent("enable", this);
21982 onEnable : function(){
21983 this.getActionEl().removeClass(this.disabledClass);
21984 this.el.dom.disabled = false;
21988 * Convenience function for setting disabled/enabled by boolean.
21989 * @param {Boolean} disabled
21991 setDisabled : function(disabled){
21992 this[disabled ? "disable" : "enable"]();
21996 * Show this component.
21997 * @return {Roo.Component} this
22000 if(this.fireEvent("beforeshow", this) !== false){
22001 this.hidden = false;
22005 this.fireEvent("show", this);
22011 onShow : function(){
22012 var ae = this.getActionEl();
22013 if(this.hideMode == 'visibility'){
22014 ae.dom.style.visibility = "visible";
22015 }else if(this.hideMode == 'offsets'){
22016 ae.removeClass('x-hidden');
22018 ae.dom.style.display = "";
22023 * Hide this component.
22024 * @return {Roo.Component} this
22027 if(this.fireEvent("beforehide", this) !== false){
22028 this.hidden = true;
22032 this.fireEvent("hide", this);
22038 onHide : function(){
22039 var ae = this.getActionEl();
22040 if(this.hideMode == 'visibility'){
22041 ae.dom.style.visibility = "hidden";
22042 }else if(this.hideMode == 'offsets'){
22043 ae.addClass('x-hidden');
22045 ae.dom.style.display = "none";
22050 * Convenience function to hide or show this component by boolean.
22051 * @param {Boolean} visible True to show, false to hide
22052 * @return {Roo.Component} this
22054 setVisible: function(visible){
22064 * Returns true if this component is visible.
22066 isVisible : function(){
22067 return this.getActionEl().isVisible();
22070 cloneConfig : function(overrides){
22071 overrides = overrides || {};
22072 var id = overrides.id || Roo.id();
22073 var cfg = Roo.applyIf(overrides, this.initialConfig);
22074 cfg.id = id; // prevent dup id
22075 return new this.constructor(cfg);
22079 * Ext JS Library 1.1.1
22080 * Copyright(c) 2006-2007, Ext JS, LLC.
22082 * Originally Released Under LGPL - original licence link has changed is not relivant.
22085 * <script type="text/javascript">
22090 * @extends Roo.Element
22091 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22092 * automatic maintaining of shadow/shim positions.
22093 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22094 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22095 * you can pass a string with a CSS class name. False turns off the shadow.
22096 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22097 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22098 * @cfg {String} cls CSS class to add to the element
22099 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22100 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22102 * @param {Object} config An object with config options.
22103 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22106 Roo.Layer = function(config, existingEl){
22107 config = config || {};
22108 var dh = Roo.DomHelper;
22109 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22111 this.dom = Roo.getDom(existingEl);
22114 var o = config.dh || {tag: "div", cls: "x-layer"};
22115 this.dom = dh.append(pel, o);
22118 this.addClass(config.cls);
22120 this.constrain = config.constrain !== false;
22121 this.visibilityMode = Roo.Element.VISIBILITY;
22123 this.id = this.dom.id = config.id;
22125 this.id = Roo.id(this.dom);
22127 this.zindex = config.zindex || this.getZIndex();
22128 this.position("absolute", this.zindex);
22130 this.shadowOffset = config.shadowOffset || 4;
22131 this.shadow = new Roo.Shadow({
22132 offset : this.shadowOffset,
22133 mode : config.shadow
22136 this.shadowOffset = 0;
22138 this.useShim = config.shim !== false && Roo.useShims;
22139 this.useDisplay = config.useDisplay;
22143 var supr = Roo.Element.prototype;
22145 // shims are shared among layer to keep from having 100 iframes
22148 Roo.extend(Roo.Layer, Roo.Element, {
22150 getZIndex : function(){
22151 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22154 getShim : function(){
22161 var shim = shims.shift();
22163 shim = this.createShim();
22164 shim.enableDisplayMode('block');
22165 shim.dom.style.display = 'none';
22166 shim.dom.style.visibility = 'visible';
22168 var pn = this.dom.parentNode;
22169 if(shim.dom.parentNode != pn){
22170 pn.insertBefore(shim.dom, this.dom);
22172 shim.setStyle('z-index', this.getZIndex()-2);
22177 hideShim : function(){
22179 this.shim.setDisplayed(false);
22180 shims.push(this.shim);
22185 disableShadow : function(){
22187 this.shadowDisabled = true;
22188 this.shadow.hide();
22189 this.lastShadowOffset = this.shadowOffset;
22190 this.shadowOffset = 0;
22194 enableShadow : function(show){
22196 this.shadowDisabled = false;
22197 this.shadowOffset = this.lastShadowOffset;
22198 delete this.lastShadowOffset;
22206 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22207 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22208 sync : function(doShow){
22209 var sw = this.shadow;
22210 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22211 var sh = this.getShim();
22213 var w = this.getWidth(),
22214 h = this.getHeight();
22216 var l = this.getLeft(true),
22217 t = this.getTop(true);
22219 if(sw && !this.shadowDisabled){
22220 if(doShow && !sw.isVisible()){
22223 sw.realign(l, t, w, h);
22229 // fit the shim behind the shadow, so it is shimmed too
22230 var a = sw.adjusts, s = sh.dom.style;
22231 s.left = (Math.min(l, l+a.l))+"px";
22232 s.top = (Math.min(t, t+a.t))+"px";
22233 s.width = (w+a.w)+"px";
22234 s.height = (h+a.h)+"px";
22241 sh.setLeftTop(l, t);
22248 destroy : function(){
22251 this.shadow.hide();
22253 this.removeAllListeners();
22254 var pn = this.dom.parentNode;
22256 pn.removeChild(this.dom);
22258 Roo.Element.uncache(this.id);
22261 remove : function(){
22266 beginUpdate : function(){
22267 this.updating = true;
22271 endUpdate : function(){
22272 this.updating = false;
22277 hideUnders : function(negOffset){
22279 this.shadow.hide();
22285 constrainXY : function(){
22286 if(this.constrain){
22287 var vw = Roo.lib.Dom.getViewWidth(),
22288 vh = Roo.lib.Dom.getViewHeight();
22289 var s = Roo.get(document).getScroll();
22291 var xy = this.getXY();
22292 var x = xy[0], y = xy[1];
22293 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22294 // only move it if it needs it
22296 // first validate right/bottom
22297 if((x + w) > vw+s.left){
22298 x = vw - w - this.shadowOffset;
22301 if((y + h) > vh+s.top){
22302 y = vh - h - this.shadowOffset;
22305 // then make sure top/left isn't negative
22316 var ay = this.avoidY;
22317 if(y <= ay && (y+h) >= ay){
22323 supr.setXY.call(this, xy);
22329 isVisible : function(){
22330 return this.visible;
22334 showAction : function(){
22335 this.visible = true; // track visibility to prevent getStyle calls
22336 if(this.useDisplay === true){
22337 this.setDisplayed("");
22338 }else if(this.lastXY){
22339 supr.setXY.call(this, this.lastXY);
22340 }else if(this.lastLT){
22341 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22346 hideAction : function(){
22347 this.visible = false;
22348 if(this.useDisplay === true){
22349 this.setDisplayed(false);
22351 this.setLeftTop(-10000,-10000);
22355 // overridden Element method
22356 setVisible : function(v, a, d, c, e){
22361 var cb = function(){
22366 }.createDelegate(this);
22367 supr.setVisible.call(this, true, true, d, cb, e);
22370 this.hideUnders(true);
22379 }.createDelegate(this);
22381 supr.setVisible.call(this, v, a, d, cb, e);
22390 storeXY : function(xy){
22391 delete this.lastLT;
22395 storeLeftTop : function(left, top){
22396 delete this.lastXY;
22397 this.lastLT = [left, top];
22401 beforeFx : function(){
22402 this.beforeAction();
22403 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22407 afterFx : function(){
22408 Roo.Layer.superclass.afterFx.apply(this, arguments);
22409 this.sync(this.isVisible());
22413 beforeAction : function(){
22414 if(!this.updating && this.shadow){
22415 this.shadow.hide();
22419 // overridden Element method
22420 setLeft : function(left){
22421 this.storeLeftTop(left, this.getTop(true));
22422 supr.setLeft.apply(this, arguments);
22426 setTop : function(top){
22427 this.storeLeftTop(this.getLeft(true), top);
22428 supr.setTop.apply(this, arguments);
22432 setLeftTop : function(left, top){
22433 this.storeLeftTop(left, top);
22434 supr.setLeftTop.apply(this, arguments);
22438 setXY : function(xy, a, d, c, e){
22440 this.beforeAction();
22442 var cb = this.createCB(c);
22443 supr.setXY.call(this, xy, a, d, cb, e);
22450 createCB : function(c){
22461 // overridden Element method
22462 setX : function(x, a, d, c, e){
22463 this.setXY([x, this.getY()], a, d, c, e);
22466 // overridden Element method
22467 setY : function(y, a, d, c, e){
22468 this.setXY([this.getX(), y], a, d, c, e);
22471 // overridden Element method
22472 setSize : function(w, h, a, d, c, e){
22473 this.beforeAction();
22474 var cb = this.createCB(c);
22475 supr.setSize.call(this, w, h, a, d, cb, e);
22481 // overridden Element method
22482 setWidth : function(w, a, d, c, e){
22483 this.beforeAction();
22484 var cb = this.createCB(c);
22485 supr.setWidth.call(this, w, a, d, cb, e);
22491 // overridden Element method
22492 setHeight : function(h, a, d, c, e){
22493 this.beforeAction();
22494 var cb = this.createCB(c);
22495 supr.setHeight.call(this, h, a, d, cb, e);
22501 // overridden Element method
22502 setBounds : function(x, y, w, h, a, d, c, e){
22503 this.beforeAction();
22504 var cb = this.createCB(c);
22506 this.storeXY([x, y]);
22507 supr.setXY.call(this, [x, y]);
22508 supr.setSize.call(this, w, h, a, d, cb, e);
22511 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22517 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22518 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22519 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22520 * @param {Number} zindex The new z-index to set
22521 * @return {this} The Layer
22523 setZIndex : function(zindex){
22524 this.zindex = zindex;
22525 this.setStyle("z-index", zindex + 2);
22527 this.shadow.setZIndex(zindex + 1);
22530 this.shim.setStyle("z-index", zindex);
22536 * Ext JS Library 1.1.1
22537 * Copyright(c) 2006-2007, Ext JS, LLC.
22539 * Originally Released Under LGPL - original licence link has changed is not relivant.
22542 * <script type="text/javascript">
22547 * @class Roo.Shadow
22548 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22549 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22550 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22552 * Create a new Shadow
22553 * @param {Object} config The config object
22555 Roo.Shadow = function(config){
22556 Roo.apply(this, config);
22557 if(typeof this.mode != "string"){
22558 this.mode = this.defaultMode;
22560 var o = this.offset, a = {h: 0};
22561 var rad = Math.floor(this.offset/2);
22562 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22568 a.l -= this.offset + rad;
22569 a.t -= this.offset + rad;
22580 a.l -= (this.offset - rad);
22581 a.t -= this.offset + rad;
22583 a.w -= (this.offset - rad)*2;
22594 a.l -= (this.offset - rad);
22595 a.t -= (this.offset - rad);
22597 a.w -= (this.offset + rad + 1);
22598 a.h -= (this.offset + rad);
22607 Roo.Shadow.prototype = {
22609 * @cfg {String} mode
22610 * The shadow display mode. Supports the following options:<br />
22611 * sides: Shadow displays on both sides and bottom only<br />
22612 * frame: Shadow displays equally on all four sides<br />
22613 * drop: Traditional bottom-right drop shadow (default)
22616 * @cfg {String} offset
22617 * The number of pixels to offset the shadow from the element (defaults to 4)
22622 defaultMode: "drop",
22625 * Displays the shadow under the target element
22626 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22628 show : function(target){
22629 target = Roo.get(target);
22631 this.el = Roo.Shadow.Pool.pull();
22632 if(this.el.dom.nextSibling != target.dom){
22633 this.el.insertBefore(target);
22636 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22638 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22641 target.getLeft(true),
22642 target.getTop(true),
22646 this.el.dom.style.display = "block";
22650 * Returns true if the shadow is visible, else false
22652 isVisible : function(){
22653 return this.el ? true : false;
22657 * Direct alignment when values are already available. Show must be called at least once before
22658 * calling this method to ensure it is initialized.
22659 * @param {Number} left The target element left position
22660 * @param {Number} top The target element top position
22661 * @param {Number} width The target element width
22662 * @param {Number} height The target element height
22664 realign : function(l, t, w, h){
22668 var a = this.adjusts, d = this.el.dom, s = d.style;
22670 s.left = (l+a.l)+"px";
22671 s.top = (t+a.t)+"px";
22672 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22674 if(s.width != sws || s.height != shs){
22678 var cn = d.childNodes;
22679 var sww = Math.max(0, (sw-12))+"px";
22680 cn[0].childNodes[1].style.width = sww;
22681 cn[1].childNodes[1].style.width = sww;
22682 cn[2].childNodes[1].style.width = sww;
22683 cn[1].style.height = Math.max(0, (sh-12))+"px";
22689 * Hides this shadow
22693 this.el.dom.style.display = "none";
22694 Roo.Shadow.Pool.push(this.el);
22700 * Adjust the z-index of this shadow
22701 * @param {Number} zindex The new z-index
22703 setZIndex : function(z){
22706 this.el.setStyle("z-index", z);
22711 // Private utility class that manages the internal Shadow cache
22712 Roo.Shadow.Pool = function(){
22714 var markup = Roo.isIE ?
22715 '<div class="x-ie-shadow"></div>' :
22716 '<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>';
22719 var sh = p.shift();
22721 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22722 sh.autoBoxAdjust = false;
22727 push : function(sh){
22733 * Ext JS Library 1.1.1
22734 * Copyright(c) 2006-2007, Ext JS, LLC.
22736 * Originally Released Under LGPL - original licence link has changed is not relivant.
22739 * <script type="text/javascript">
22743 * @class Roo.BoxComponent
22744 * @extends Roo.Component
22745 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22746 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22747 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22748 * layout containers.
22750 * @param {Roo.Element/String/Object} config The configuration options.
22752 Roo.BoxComponent = function(config){
22753 Roo.Component.call(this, config);
22757 * Fires after the component is resized.
22758 * @param {Roo.Component} this
22759 * @param {Number} adjWidth The box-adjusted width that was set
22760 * @param {Number} adjHeight The box-adjusted height that was set
22761 * @param {Number} rawWidth The width that was originally specified
22762 * @param {Number} rawHeight The height that was originally specified
22767 * Fires after the component is moved.
22768 * @param {Roo.Component} this
22769 * @param {Number} x The new x position
22770 * @param {Number} y The new y position
22776 Roo.extend(Roo.BoxComponent, Roo.Component, {
22777 // private, set in afterRender to signify that the component has been rendered
22779 // private, used to defer height settings to subclasses
22780 deferHeight: false,
22781 /** @cfg {Number} width
22782 * width (optional) size of component
22784 /** @cfg {Number} height
22785 * height (optional) size of component
22789 * Sets the width and height of the component. This method fires the resize event. This method can accept
22790 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22791 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22792 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22793 * @return {Roo.BoxComponent} this
22795 setSize : function(w, h){
22796 // support for standard size objects
22797 if(typeof w == 'object'){
22802 if(!this.boxReady){
22808 // prevent recalcs when not needed
22809 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22812 this.lastSize = {width: w, height: h};
22814 var adj = this.adjustSize(w, h);
22815 var aw = adj.width, ah = adj.height;
22816 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22817 var rz = this.getResizeEl();
22818 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22819 rz.setSize(aw, ah);
22820 }else if(!this.deferHeight && ah !== undefined){
22822 }else if(aw !== undefined){
22825 this.onResize(aw, ah, w, h);
22826 this.fireEvent('resize', this, aw, ah, w, h);
22832 * Gets the current size of the component's underlying element.
22833 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22835 getSize : function(){
22836 return this.el.getSize();
22840 * Gets the current XY position of the component's underlying element.
22841 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22842 * @return {Array} The XY position of the element (e.g., [100, 200])
22844 getPosition : function(local){
22845 if(local === true){
22846 return [this.el.getLeft(true), this.el.getTop(true)];
22848 return this.xy || this.el.getXY();
22852 * Gets the current box measurements of the component's underlying element.
22853 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22854 * @returns {Object} box An object in the format {x, y, width, height}
22856 getBox : function(local){
22857 var s = this.el.getSize();
22859 s.x = this.el.getLeft(true);
22860 s.y = this.el.getTop(true);
22862 var xy = this.xy || this.el.getXY();
22870 * Sets the current box measurements of the component's underlying element.
22871 * @param {Object} box An object in the format {x, y, width, height}
22872 * @returns {Roo.BoxComponent} this
22874 updateBox : function(box){
22875 this.setSize(box.width, box.height);
22876 this.setPagePosition(box.x, box.y);
22881 getResizeEl : function(){
22882 return this.resizeEl || this.el;
22886 getPositionEl : function(){
22887 return this.positionEl || this.el;
22891 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22892 * This method fires the move event.
22893 * @param {Number} left The new left
22894 * @param {Number} top The new top
22895 * @returns {Roo.BoxComponent} this
22897 setPosition : function(x, y){
22900 if(!this.boxReady){
22903 var adj = this.adjustPosition(x, y);
22904 var ax = adj.x, ay = adj.y;
22906 var el = this.getPositionEl();
22907 if(ax !== undefined || ay !== undefined){
22908 if(ax !== undefined && ay !== undefined){
22909 el.setLeftTop(ax, ay);
22910 }else if(ax !== undefined){
22912 }else if(ay !== undefined){
22915 this.onPosition(ax, ay);
22916 this.fireEvent('move', this, ax, ay);
22922 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22923 * This method fires the move event.
22924 * @param {Number} x The new x position
22925 * @param {Number} y The new y position
22926 * @returns {Roo.BoxComponent} this
22928 setPagePosition : function(x, y){
22931 if(!this.boxReady){
22934 if(x === undefined || y === undefined){ // cannot translate undefined points
22937 var p = this.el.translatePoints(x, y);
22938 this.setPosition(p.left, p.top);
22943 onRender : function(ct, position){
22944 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22946 this.resizeEl = Roo.get(this.resizeEl);
22948 if(this.positionEl){
22949 this.positionEl = Roo.get(this.positionEl);
22954 afterRender : function(){
22955 Roo.BoxComponent.superclass.afterRender.call(this);
22956 this.boxReady = true;
22957 this.setSize(this.width, this.height);
22958 if(this.x || this.y){
22959 this.setPosition(this.x, this.y);
22961 if(this.pageX || this.pageY){
22962 this.setPagePosition(this.pageX, this.pageY);
22967 * Force the component's size to recalculate based on the underlying element's current height and width.
22968 * @returns {Roo.BoxComponent} this
22970 syncSize : function(){
22971 delete this.lastSize;
22972 this.setSize(this.el.getWidth(), this.el.getHeight());
22977 * Called after the component is resized, this method is empty by default but can be implemented by any
22978 * subclass that needs to perform custom logic after a resize occurs.
22979 * @param {Number} adjWidth The box-adjusted width that was set
22980 * @param {Number} adjHeight The box-adjusted height that was set
22981 * @param {Number} rawWidth The width that was originally specified
22982 * @param {Number} rawHeight The height that was originally specified
22984 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22989 * Called after the component is moved, this method is empty by default but can be implemented by any
22990 * subclass that needs to perform custom logic after a move occurs.
22991 * @param {Number} x The new x position
22992 * @param {Number} y The new y position
22994 onPosition : function(x, y){
22999 adjustSize : function(w, h){
23000 if(this.autoWidth){
23003 if(this.autoHeight){
23006 return {width : w, height: h};
23010 adjustPosition : function(x, y){
23011 return {x : x, y: y};
23015 * Ext JS Library 1.1.1
23016 * Copyright(c) 2006-2007, Ext JS, LLC.
23018 * Originally Released Under LGPL - original licence link has changed is not relivant.
23021 * <script type="text/javascript">
23026 * @class Roo.SplitBar
23027 * @extends Roo.util.Observable
23028 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23032 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23033 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23034 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23035 split.minSize = 100;
23036 split.maxSize = 600;
23037 split.animate = true;
23038 split.on('moved', splitterMoved);
23041 * Create a new SplitBar
23042 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23043 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23044 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23045 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23046 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23047 position of the SplitBar).
23049 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23052 this.el = Roo.get(dragElement, true);
23053 this.el.dom.unselectable = "on";
23055 this.resizingEl = Roo.get(resizingElement, true);
23059 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23060 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23063 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23066 * The minimum size of the resizing element. (Defaults to 0)
23072 * The maximum size of the resizing element. (Defaults to 2000)
23075 this.maxSize = 2000;
23078 * Whether to animate the transition to the new size
23081 this.animate = false;
23084 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23087 this.useShim = false;
23092 if(!existingProxy){
23094 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23096 this.proxy = Roo.get(existingProxy).dom;
23099 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23102 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23105 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23108 this.dragSpecs = {};
23111 * @private The adapter to use to positon and resize elements
23113 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23114 this.adapter.init(this);
23116 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23118 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23119 this.el.addClass("x-splitbar-h");
23122 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23123 this.el.addClass("x-splitbar-v");
23129 * Fires when the splitter is moved (alias for {@link #event-moved})
23130 * @param {Roo.SplitBar} this
23131 * @param {Number} newSize the new width or height
23136 * Fires when the splitter is moved
23137 * @param {Roo.SplitBar} this
23138 * @param {Number} newSize the new width or height
23142 * @event beforeresize
23143 * Fires before the splitter is dragged
23144 * @param {Roo.SplitBar} this
23146 "beforeresize" : true,
23148 "beforeapply" : true
23151 Roo.util.Observable.call(this);
23154 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23155 onStartProxyDrag : function(x, y){
23156 this.fireEvent("beforeresize", this);
23158 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23160 o.enableDisplayMode("block");
23161 // all splitbars share the same overlay
23162 Roo.SplitBar.prototype.overlay = o;
23164 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23165 this.overlay.show();
23166 Roo.get(this.proxy).setDisplayed("block");
23167 var size = this.adapter.getElementSize(this);
23168 this.activeMinSize = this.getMinimumSize();;
23169 this.activeMaxSize = this.getMaximumSize();;
23170 var c1 = size - this.activeMinSize;
23171 var c2 = Math.max(this.activeMaxSize - size, 0);
23172 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23173 this.dd.resetConstraints();
23174 this.dd.setXConstraint(
23175 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23176 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23178 this.dd.setYConstraint(0, 0);
23180 this.dd.resetConstraints();
23181 this.dd.setXConstraint(0, 0);
23182 this.dd.setYConstraint(
23183 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23184 this.placement == Roo.SplitBar.TOP ? c2 : c1
23187 this.dragSpecs.startSize = size;
23188 this.dragSpecs.startPoint = [x, y];
23189 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23193 * @private Called after the drag operation by the DDProxy
23195 onEndProxyDrag : function(e){
23196 Roo.get(this.proxy).setDisplayed(false);
23197 var endPoint = Roo.lib.Event.getXY(e);
23199 this.overlay.hide();
23202 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23203 newSize = this.dragSpecs.startSize +
23204 (this.placement == Roo.SplitBar.LEFT ?
23205 endPoint[0] - this.dragSpecs.startPoint[0] :
23206 this.dragSpecs.startPoint[0] - endPoint[0]
23209 newSize = this.dragSpecs.startSize +
23210 (this.placement == Roo.SplitBar.TOP ?
23211 endPoint[1] - this.dragSpecs.startPoint[1] :
23212 this.dragSpecs.startPoint[1] - endPoint[1]
23215 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23216 if(newSize != this.dragSpecs.startSize){
23217 if(this.fireEvent('beforeapply', this, newSize) !== false){
23218 this.adapter.setElementSize(this, newSize);
23219 this.fireEvent("moved", this, newSize);
23220 this.fireEvent("resize", this, newSize);
23226 * Get the adapter this SplitBar uses
23227 * @return The adapter object
23229 getAdapter : function(){
23230 return this.adapter;
23234 * Set the adapter this SplitBar uses
23235 * @param {Object} adapter A SplitBar adapter object
23237 setAdapter : function(adapter){
23238 this.adapter = adapter;
23239 this.adapter.init(this);
23243 * Gets the minimum size for the resizing element
23244 * @return {Number} The minimum size
23246 getMinimumSize : function(){
23247 return this.minSize;
23251 * Sets the minimum size for the resizing element
23252 * @param {Number} minSize The minimum size
23254 setMinimumSize : function(minSize){
23255 this.minSize = minSize;
23259 * Gets the maximum size for the resizing element
23260 * @return {Number} The maximum size
23262 getMaximumSize : function(){
23263 return this.maxSize;
23267 * Sets the maximum size for the resizing element
23268 * @param {Number} maxSize The maximum size
23270 setMaximumSize : function(maxSize){
23271 this.maxSize = maxSize;
23275 * Sets the initialize size for the resizing element
23276 * @param {Number} size The initial size
23278 setCurrentSize : function(size){
23279 var oldAnimate = this.animate;
23280 this.animate = false;
23281 this.adapter.setElementSize(this, size);
23282 this.animate = oldAnimate;
23286 * Destroy this splitbar.
23287 * @param {Boolean} removeEl True to remove the element
23289 destroy : function(removeEl){
23291 this.shim.remove();
23294 this.proxy.parentNode.removeChild(this.proxy);
23302 * @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.
23304 Roo.SplitBar.createProxy = function(dir){
23305 var proxy = new Roo.Element(document.createElement("div"));
23306 proxy.unselectable();
23307 var cls = 'x-splitbar-proxy';
23308 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23309 document.body.appendChild(proxy.dom);
23314 * @class Roo.SplitBar.BasicLayoutAdapter
23315 * Default Adapter. It assumes the splitter and resizing element are not positioned
23316 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23318 Roo.SplitBar.BasicLayoutAdapter = function(){
23321 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23322 // do nothing for now
23323 init : function(s){
23327 * Called before drag operations to get the current size of the resizing element.
23328 * @param {Roo.SplitBar} s The SplitBar using this adapter
23330 getElementSize : function(s){
23331 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23332 return s.resizingEl.getWidth();
23334 return s.resizingEl.getHeight();
23339 * Called after drag operations to set the size of the resizing element.
23340 * @param {Roo.SplitBar} s The SplitBar using this adapter
23341 * @param {Number} newSize The new size to set
23342 * @param {Function} onComplete A function to be invoked when resizing is complete
23344 setElementSize : function(s, newSize, onComplete){
23345 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23347 s.resizingEl.setWidth(newSize);
23349 onComplete(s, newSize);
23352 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23357 s.resizingEl.setHeight(newSize);
23359 onComplete(s, newSize);
23362 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23369 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23370 * @extends Roo.SplitBar.BasicLayoutAdapter
23371 * Adapter that moves the splitter element to align with the resized sizing element.
23372 * Used with an absolute positioned SplitBar.
23373 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23374 * document.body, make sure you assign an id to the body element.
23376 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23377 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23378 this.container = Roo.get(container);
23381 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23382 init : function(s){
23383 this.basic.init(s);
23386 getElementSize : function(s){
23387 return this.basic.getElementSize(s);
23390 setElementSize : function(s, newSize, onComplete){
23391 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23394 moveSplitter : function(s){
23395 var yes = Roo.SplitBar;
23396 switch(s.placement){
23398 s.el.setX(s.resizingEl.getRight());
23401 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23404 s.el.setY(s.resizingEl.getBottom());
23407 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23414 * Orientation constant - Create a vertical SplitBar
23418 Roo.SplitBar.VERTICAL = 1;
23421 * Orientation constant - Create a horizontal SplitBar
23425 Roo.SplitBar.HORIZONTAL = 2;
23428 * Placement constant - The resizing element is to the left of the splitter element
23432 Roo.SplitBar.LEFT = 1;
23435 * Placement constant - The resizing element is to the right of the splitter element
23439 Roo.SplitBar.RIGHT = 2;
23442 * Placement constant - The resizing element is positioned above the splitter element
23446 Roo.SplitBar.TOP = 3;
23449 * Placement constant - The resizing element is positioned under splitter element
23453 Roo.SplitBar.BOTTOM = 4;
23456 * Ext JS Library 1.1.1
23457 * Copyright(c) 2006-2007, Ext JS, LLC.
23459 * Originally Released Under LGPL - original licence link has changed is not relivant.
23462 * <script type="text/javascript">
23467 * @extends Roo.util.Observable
23468 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23469 * This class also supports single and multi selection modes. <br>
23470 * Create a data model bound view:
23472 var store = new Roo.data.Store(...);
23474 var view = new Roo.View({
23476 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23478 singleSelect: true,
23479 selectedClass: "ydataview-selected",
23483 // listen for node click?
23484 view.on("click", function(vw, index, node, e){
23485 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23489 dataModel.load("foobar.xml");
23491 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23493 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23494 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23496 * Note: old style constructor is still suported (container, template, config)
23499 * Create a new View
23500 * @param {Object} config The config object
23503 Roo.View = function(config, depreciated_tpl, depreciated_config){
23505 if (typeof(depreciated_tpl) == 'undefined') {
23506 // new way.. - universal constructor.
23507 Roo.apply(this, config);
23508 this.el = Roo.get(this.el);
23511 this.el = Roo.get(config);
23512 this.tpl = depreciated_tpl;
23513 Roo.apply(this, depreciated_config);
23517 if(typeof(this.tpl) == "string"){
23518 this.tpl = new Roo.Template(this.tpl);
23520 // support xtype ctors..
23521 this.tpl = new Roo.factory(this.tpl, Roo);
23525 this.tpl.compile();
23532 * @event beforeclick
23533 * Fires before a click is processed. Returns false to cancel the default action.
23534 * @param {Roo.View} this
23535 * @param {Number} index The index of the target node
23536 * @param {HTMLElement} node The target node
23537 * @param {Roo.EventObject} e The raw event object
23539 "beforeclick" : true,
23542 * Fires when a template node is clicked.
23543 * @param {Roo.View} this
23544 * @param {Number} index The index of the target node
23545 * @param {HTMLElement} node The target node
23546 * @param {Roo.EventObject} e The raw event object
23551 * Fires when a template node is double clicked.
23552 * @param {Roo.View} this
23553 * @param {Number} index The index of the target node
23554 * @param {HTMLElement} node The target node
23555 * @param {Roo.EventObject} e The raw event object
23559 * @event contextmenu
23560 * Fires when a template node is right clicked.
23561 * @param {Roo.View} this
23562 * @param {Number} index The index of the target node
23563 * @param {HTMLElement} node The target node
23564 * @param {Roo.EventObject} e The raw event object
23566 "contextmenu" : true,
23568 * @event selectionchange
23569 * Fires when the selected nodes change.
23570 * @param {Roo.View} this
23571 * @param {Array} selections Array of the selected nodes
23573 "selectionchange" : true,
23576 * @event beforeselect
23577 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23578 * @param {Roo.View} this
23579 * @param {HTMLElement} node The node to be selected
23580 * @param {Array} selections Array of currently selected nodes
23582 "beforeselect" : true
23586 "click": this.onClick,
23587 "dblclick": this.onDblClick,
23588 "contextmenu": this.onContextMenu,
23592 this.selections = [];
23594 this.cmp = new Roo.CompositeElementLite([]);
23596 this.store = Roo.factory(this.store, Roo.data);
23597 this.setStore(this.store, true);
23599 Roo.View.superclass.constructor.call(this);
23602 Roo.extend(Roo.View, Roo.util.Observable, {
23605 * @cfg {Roo.data.Store} store Data store to load data from.
23610 * @cfg {String|Roo.Element} el The container element.
23615 * @cfg {String|Roo.Template} tpl The template used by this View
23620 * @cfg {String} selectedClass The css class to add to selected nodes
23622 selectedClass : "x-view-selected",
23624 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23628 * @cfg {Boolean} multiSelect Allow multiple selection
23631 multiSelect : false,
23633 * @cfg {Boolean} singleSelect Allow single selection
23635 singleSelect: false,
23638 * Returns the element this view is bound to.
23639 * @return {Roo.Element}
23641 getEl : function(){
23646 * Refreshes the view.
23648 refresh : function(){
23650 this.clearSelections();
23651 this.el.update("");
23653 var records = this.store.getRange();
23654 if(records.length < 1){
23655 this.el.update(this.emptyText);
23658 for(var i = 0, len = records.length; i < len; i++){
23659 var data = this.prepareData(records[i].data, i, records[i]);
23660 html[html.length] = t.apply(data);
23662 this.el.update(html.join(""));
23663 this.nodes = this.el.dom.childNodes;
23664 this.updateIndexes(0);
23668 * Function to override to reformat the data that is sent to
23669 * the template for each node.
23670 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23671 * a JSON object for an UpdateManager bound view).
23673 prepareData : function(data){
23677 onUpdate : function(ds, record){
23678 this.clearSelections();
23679 var index = this.store.indexOf(record);
23680 var n = this.nodes[index];
23681 this.tpl.insertBefore(n, this.prepareData(record.data));
23682 n.parentNode.removeChild(n);
23683 this.updateIndexes(index, index);
23686 onAdd : function(ds, records, index){
23687 this.clearSelections();
23688 if(this.nodes.length == 0){
23692 var n = this.nodes[index];
23693 for(var i = 0, len = records.length; i < len; i++){
23694 var d = this.prepareData(records[i].data);
23696 this.tpl.insertBefore(n, d);
23698 this.tpl.append(this.el, d);
23701 this.updateIndexes(index);
23704 onRemove : function(ds, record, index){
23705 this.clearSelections();
23706 this.el.dom.removeChild(this.nodes[index]);
23707 this.updateIndexes(index);
23711 * Refresh an individual node.
23712 * @param {Number} index
23714 refreshNode : function(index){
23715 this.onUpdate(this.store, this.store.getAt(index));
23718 updateIndexes : function(startIndex, endIndex){
23719 var ns = this.nodes;
23720 startIndex = startIndex || 0;
23721 endIndex = endIndex || ns.length - 1;
23722 for(var i = startIndex; i <= endIndex; i++){
23723 ns[i].nodeIndex = i;
23728 * Changes the data store this view uses and refresh the view.
23729 * @param {Store} store
23731 setStore : function(store, initial){
23732 if(!initial && this.store){
23733 this.store.un("datachanged", this.refresh);
23734 this.store.un("add", this.onAdd);
23735 this.store.un("remove", this.onRemove);
23736 this.store.un("update", this.onUpdate);
23737 this.store.un("clear", this.refresh);
23741 store.on("datachanged", this.refresh, this);
23742 store.on("add", this.onAdd, this);
23743 store.on("remove", this.onRemove, this);
23744 store.on("update", this.onUpdate, this);
23745 store.on("clear", this.refresh, this);
23754 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23755 * @param {HTMLElement} node
23756 * @return {HTMLElement} The template node
23758 findItemFromChild : function(node){
23759 var el = this.el.dom;
23760 if(!node || node.parentNode == el){
23763 var p = node.parentNode;
23764 while(p && p != el){
23765 if(p.parentNode == el){
23774 onClick : function(e){
23775 var item = this.findItemFromChild(e.getTarget());
23777 var index = this.indexOf(item);
23778 if(this.onItemClick(item, index, e) !== false){
23779 this.fireEvent("click", this, index, item, e);
23782 this.clearSelections();
23787 onContextMenu : function(e){
23788 var item = this.findItemFromChild(e.getTarget());
23790 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23795 onDblClick : function(e){
23796 var item = this.findItemFromChild(e.getTarget());
23798 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23802 onItemClick : function(item, index, e){
23803 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23806 if(this.multiSelect || this.singleSelect){
23807 if(this.multiSelect && e.shiftKey && this.lastSelection){
23808 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23810 this.select(item, this.multiSelect && e.ctrlKey);
23811 this.lastSelection = item;
23813 e.preventDefault();
23819 * Get the number of selected nodes.
23822 getSelectionCount : function(){
23823 return this.selections.length;
23827 * Get the currently selected nodes.
23828 * @return {Array} An array of HTMLElements
23830 getSelectedNodes : function(){
23831 return this.selections;
23835 * Get the indexes of the selected nodes.
23838 getSelectedIndexes : function(){
23839 var indexes = [], s = this.selections;
23840 for(var i = 0, len = s.length; i < len; i++){
23841 indexes.push(s[i].nodeIndex);
23847 * Clear all selections
23848 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23850 clearSelections : function(suppressEvent){
23851 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23852 this.cmp.elements = this.selections;
23853 this.cmp.removeClass(this.selectedClass);
23854 this.selections = [];
23855 if(!suppressEvent){
23856 this.fireEvent("selectionchange", this, this.selections);
23862 * Returns true if the passed node is selected
23863 * @param {HTMLElement/Number} node The node or node index
23864 * @return {Boolean}
23866 isSelected : function(node){
23867 var s = this.selections;
23871 node = this.getNode(node);
23872 return s.indexOf(node) !== -1;
23877 * @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
23878 * @param {Boolean} keepExisting (optional) true to keep existing selections
23879 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23881 select : function(nodeInfo, keepExisting, suppressEvent){
23882 if(nodeInfo instanceof Array){
23884 this.clearSelections(true);
23886 for(var i = 0, len = nodeInfo.length; i < len; i++){
23887 this.select(nodeInfo[i], true, true);
23890 var node = this.getNode(nodeInfo);
23891 if(node && !this.isSelected(node)){
23893 this.clearSelections(true);
23895 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23896 Roo.fly(node).addClass(this.selectedClass);
23897 this.selections.push(node);
23898 if(!suppressEvent){
23899 this.fireEvent("selectionchange", this, this.selections);
23907 * Gets a template node.
23908 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23909 * @return {HTMLElement} The node or null if it wasn't found
23911 getNode : function(nodeInfo){
23912 if(typeof nodeInfo == "string"){
23913 return document.getElementById(nodeInfo);
23914 }else if(typeof nodeInfo == "number"){
23915 return this.nodes[nodeInfo];
23921 * Gets a range template nodes.
23922 * @param {Number} startIndex
23923 * @param {Number} endIndex
23924 * @return {Array} An array of nodes
23926 getNodes : function(start, end){
23927 var ns = this.nodes;
23928 start = start || 0;
23929 end = typeof end == "undefined" ? ns.length - 1 : end;
23932 for(var i = start; i <= end; i++){
23936 for(var i = start; i >= end; i--){
23944 * Finds the index of the passed node
23945 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23946 * @return {Number} The index of the node or -1
23948 indexOf : function(node){
23949 node = this.getNode(node);
23950 if(typeof node.nodeIndex == "number"){
23951 return node.nodeIndex;
23953 var ns = this.nodes;
23954 for(var i = 0, len = ns.length; i < len; i++){
23964 * Ext JS Library 1.1.1
23965 * Copyright(c) 2006-2007, Ext JS, LLC.
23967 * Originally Released Under LGPL - original licence link has changed is not relivant.
23970 * <script type="text/javascript">
23974 * @class Roo.JsonView
23975 * @extends Roo.View
23976 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23978 var view = new Roo.JsonView({
23979 container: "my-element",
23980 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
23985 // listen for node click?
23986 view.on("click", function(vw, index, node, e){
23987 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23990 // direct load of JSON data
23991 view.load("foobar.php");
23993 // Example from my blog list
23994 var tpl = new Roo.Template(
23995 '<div class="entry">' +
23996 '<a class="entry-title" href="{link}">{title}</a>' +
23997 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23998 "</div><hr />"
24001 var moreView = new Roo.JsonView({
24002 container : "entry-list",
24006 moreView.on("beforerender", this.sortEntries, this);
24008 url: "/blog/get-posts.php",
24009 params: "allposts=true",
24010 text: "Loading Blog Entries..."
24014 * Note: old code is supported with arguments : (container, template, config)
24018 * Create a new JsonView
24020 * @param {Object} config The config object
24023 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24026 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24028 var um = this.el.getUpdateManager();
24029 um.setRenderer(this);
24030 um.on("update", this.onLoad, this);
24031 um.on("failure", this.onLoadException, this);
24034 * @event beforerender
24035 * Fires before rendering of the downloaded JSON data.
24036 * @param {Roo.JsonView} this
24037 * @param {Object} data The JSON data loaded
24041 * Fires when data is loaded.
24042 * @param {Roo.JsonView} this
24043 * @param {Object} data The JSON data loaded
24044 * @param {Object} response The raw Connect response object
24047 * @event loadexception
24048 * Fires when loading fails.
24049 * @param {Roo.JsonView} this
24050 * @param {Object} response The raw Connect response object
24053 'beforerender' : true,
24055 'loadexception' : true
24058 Roo.extend(Roo.JsonView, Roo.View, {
24060 * @type {String} The root property in the loaded JSON object that contains the data
24065 * Refreshes the view.
24067 refresh : function(){
24068 this.clearSelections();
24069 this.el.update("");
24071 var o = this.jsonData;
24072 if(o && o.length > 0){
24073 for(var i = 0, len = o.length; i < len; i++){
24074 var data = this.prepareData(o[i], i, o);
24075 html[html.length] = this.tpl.apply(data);
24078 html.push(this.emptyText);
24080 this.el.update(html.join(""));
24081 this.nodes = this.el.dom.childNodes;
24082 this.updateIndexes(0);
24086 * 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.
24087 * @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:
24090 url: "your-url.php",
24091 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24092 callback: yourFunction,
24093 scope: yourObject, //(optional scope)
24096 text: "Loading...",
24101 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24102 * 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.
24103 * @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}
24104 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24105 * @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.
24108 var um = this.el.getUpdateManager();
24109 um.update.apply(um, arguments);
24112 render : function(el, response){
24113 this.clearSelections();
24114 this.el.update("");
24117 o = Roo.util.JSON.decode(response.responseText);
24120 o = o[this.jsonRoot];
24125 * The current JSON data or null
24128 this.beforeRender();
24133 * Get the number of records in the current JSON dataset
24136 getCount : function(){
24137 return this.jsonData ? this.jsonData.length : 0;
24141 * Returns the JSON object for the specified node(s)
24142 * @param {HTMLElement/Array} node The node or an array of nodes
24143 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24144 * you get the JSON object for the node
24146 getNodeData : function(node){
24147 if(node instanceof Array){
24149 for(var i = 0, len = node.length; i < len; i++){
24150 data.push(this.getNodeData(node[i]));
24154 return this.jsonData[this.indexOf(node)] || null;
24157 beforeRender : function(){
24158 this.snapshot = this.jsonData;
24160 this.sort.apply(this, this.sortInfo);
24162 this.fireEvent("beforerender", this, this.jsonData);
24165 onLoad : function(el, o){
24166 this.fireEvent("load", this, this.jsonData, o);
24169 onLoadException : function(el, o){
24170 this.fireEvent("loadexception", this, o);
24174 * Filter the data by a specific property.
24175 * @param {String} property A property on your JSON objects
24176 * @param {String/RegExp} value Either string that the property values
24177 * should start with, or a RegExp to test against the property
24179 filter : function(property, value){
24182 var ss = this.snapshot;
24183 if(typeof value == "string"){
24184 var vlen = value.length;
24186 this.clearFilter();
24189 value = value.toLowerCase();
24190 for(var i = 0, len = ss.length; i < len; i++){
24192 if(o[property].substr(0, vlen).toLowerCase() == value){
24196 } else if(value.exec){ // regex?
24197 for(var i = 0, len = ss.length; i < len; i++){
24199 if(value.test(o[property])){
24206 this.jsonData = data;
24212 * Filter by a function. The passed function will be called with each
24213 * object in the current dataset. If the function returns true the value is kept,
24214 * otherwise it is filtered.
24215 * @param {Function} fn
24216 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24218 filterBy : function(fn, scope){
24221 var ss = this.snapshot;
24222 for(var i = 0, len = ss.length; i < len; i++){
24224 if(fn.call(scope || this, o)){
24228 this.jsonData = data;
24234 * Clears the current filter.
24236 clearFilter : function(){
24237 if(this.snapshot && this.jsonData != this.snapshot){
24238 this.jsonData = this.snapshot;
24245 * Sorts the data for this view and refreshes it.
24246 * @param {String} property A property on your JSON objects to sort on
24247 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24248 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24250 sort : function(property, dir, sortType){
24251 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24254 var dsc = dir && dir.toLowerCase() == "desc";
24255 var f = function(o1, o2){
24256 var v1 = sortType ? sortType(o1[p]) : o1[p];
24257 var v2 = sortType ? sortType(o2[p]) : o2[p];
24260 return dsc ? +1 : -1;
24261 } else if(v1 > v2){
24262 return dsc ? -1 : +1;
24267 this.jsonData.sort(f);
24269 if(this.jsonData != this.snapshot){
24270 this.snapshot.sort(f);
24276 * Ext JS Library 1.1.1
24277 * Copyright(c) 2006-2007, Ext JS, LLC.
24279 * Originally Released Under LGPL - original licence link has changed is not relivant.
24282 * <script type="text/javascript">
24287 * @class Roo.ColorPalette
24288 * @extends Roo.Component
24289 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24290 * Here's an example of typical usage:
24292 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24293 cp.render('my-div');
24295 cp.on('select', function(palette, selColor){
24296 // do something with selColor
24300 * Create a new ColorPalette
24301 * @param {Object} config The config object
24303 Roo.ColorPalette = function(config){
24304 Roo.ColorPalette.superclass.constructor.call(this, config);
24308 * Fires when a color is selected
24309 * @param {ColorPalette} this
24310 * @param {String} color The 6-digit color hex code (without the # symbol)
24316 this.on("select", this.handler, this.scope, true);
24319 Roo.extend(Roo.ColorPalette, Roo.Component, {
24321 * @cfg {String} itemCls
24322 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24324 itemCls : "x-color-palette",
24326 * @cfg {String} value
24327 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24328 * the hex codes are case-sensitive.
24331 clickEvent:'click',
24333 ctype: "Roo.ColorPalette",
24336 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24338 allowReselect : false,
24341 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24342 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24343 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24344 * of colors with the width setting until the box is symmetrical.</p>
24345 * <p>You can override individual colors if needed:</p>
24347 var cp = new Roo.ColorPalette();
24348 cp.colors[0] = "FF0000"; // change the first box to red
24351 Or you can provide a custom array of your own for complete control:
24353 var cp = new Roo.ColorPalette();
24354 cp.colors = ["000000", "993300", "333300"];
24359 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24360 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24361 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24362 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24363 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24367 onRender : function(container, position){
24368 var t = new Roo.MasterTemplate(
24369 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24371 var c = this.colors;
24372 for(var i = 0, len = c.length; i < len; i++){
24375 var el = document.createElement("div");
24376 el.className = this.itemCls;
24378 container.dom.insertBefore(el, position);
24379 this.el = Roo.get(el);
24380 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24381 if(this.clickEvent != 'click'){
24382 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24387 afterRender : function(){
24388 Roo.ColorPalette.superclass.afterRender.call(this);
24390 var s = this.value;
24397 handleClick : function(e, t){
24398 e.preventDefault();
24399 if(!this.disabled){
24400 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24401 this.select(c.toUpperCase());
24406 * Selects the specified color in the palette (fires the select event)
24407 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24409 select : function(color){
24410 color = color.replace("#", "");
24411 if(color != this.value || this.allowReselect){
24414 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24416 el.child("a.color-"+color).addClass("x-color-palette-sel");
24417 this.value = color;
24418 this.fireEvent("select", this, color);
24423 * Ext JS Library 1.1.1
24424 * Copyright(c) 2006-2007, Ext JS, LLC.
24426 * Originally Released Under LGPL - original licence link has changed is not relivant.
24429 * <script type="text/javascript">
24433 * @class Roo.DatePicker
24434 * @extends Roo.Component
24435 * Simple date picker class.
24437 * Create a new DatePicker
24438 * @param {Object} config The config object
24440 Roo.DatePicker = function(config){
24441 Roo.DatePicker.superclass.constructor.call(this, config);
24443 this.value = config && config.value ?
24444 config.value.clearTime() : new Date().clearTime();
24449 * Fires when a date is selected
24450 * @param {DatePicker} this
24451 * @param {Date} date The selected date
24457 this.on("select", this.handler, this.scope || this);
24459 // build the disabledDatesRE
24460 if(!this.disabledDatesRE && this.disabledDates){
24461 var dd = this.disabledDates;
24463 for(var i = 0; i < dd.length; i++){
24465 if(i != dd.length-1) re += "|";
24467 this.disabledDatesRE = new RegExp(re + ")");
24471 Roo.extend(Roo.DatePicker, Roo.Component, {
24473 * @cfg {String} todayText
24474 * The text to display on the button that selects the current date (defaults to "Today")
24476 todayText : "Today",
24478 * @cfg {String} okText
24479 * The text to display on the ok button
24481 okText : " OK ", //   to give the user extra clicking room
24483 * @cfg {String} cancelText
24484 * The text to display on the cancel button
24486 cancelText : "Cancel",
24488 * @cfg {String} todayTip
24489 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24491 todayTip : "{0} (Spacebar)",
24493 * @cfg {Date} minDate
24494 * Minimum allowable date (JavaScript date object, defaults to null)
24498 * @cfg {Date} maxDate
24499 * Maximum allowable date (JavaScript date object, defaults to null)
24503 * @cfg {String} minText
24504 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24506 minText : "This date is before the minimum date",
24508 * @cfg {String} maxText
24509 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24511 maxText : "This date is after the maximum date",
24513 * @cfg {String} format
24514 * The default date format string which can be overriden for localization support. The format must be
24515 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24519 * @cfg {Array} disabledDays
24520 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24522 disabledDays : null,
24524 * @cfg {String} disabledDaysText
24525 * The tooltip to display when the date falls on a disabled day (defaults to "")
24527 disabledDaysText : "",
24529 * @cfg {RegExp} disabledDatesRE
24530 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24532 disabledDatesRE : null,
24534 * @cfg {String} disabledDatesText
24535 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24537 disabledDatesText : "",
24539 * @cfg {Boolean} constrainToViewport
24540 * True to constrain the date picker to the viewport (defaults to true)
24542 constrainToViewport : true,
24544 * @cfg {Array} monthNames
24545 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24547 monthNames : Date.monthNames,
24549 * @cfg {Array} dayNames
24550 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24552 dayNames : Date.dayNames,
24554 * @cfg {String} nextText
24555 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24557 nextText: 'Next Month (Control+Right)',
24559 * @cfg {String} prevText
24560 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24562 prevText: 'Previous Month (Control+Left)',
24564 * @cfg {String} monthYearText
24565 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24567 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24569 * @cfg {Number} startDay
24570 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24574 * @cfg {Bool} showClear
24575 * Show a clear button (usefull for date form elements that can be blank.)
24581 * Sets the value of the date field
24582 * @param {Date} value The date to set
24584 setValue : function(value){
24585 var old = this.value;
24586 this.value = value.clearTime(true);
24588 this.update(this.value);
24593 * Gets the current selected value of the date field
24594 * @return {Date} The selected date
24596 getValue : function(){
24601 focus : function(){
24603 this.update(this.activeDate);
24608 onRender : function(container, position){
24610 '<table cellspacing="0">',
24611 '<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>',
24612 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24613 var dn = this.dayNames;
24614 for(var i = 0; i < 7; i++){
24615 var d = this.startDay+i;
24619 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24621 m[m.length] = "</tr></thead><tbody><tr>";
24622 for(var i = 0; i < 42; i++) {
24623 if(i % 7 == 0 && i != 0){
24624 m[m.length] = "</tr><tr>";
24626 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24628 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24629 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24631 var el = document.createElement("div");
24632 el.className = "x-date-picker";
24633 el.innerHTML = m.join("");
24635 container.dom.insertBefore(el, position);
24637 this.el = Roo.get(el);
24638 this.eventEl = Roo.get(el.firstChild);
24640 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24641 handler: this.showPrevMonth,
24643 preventDefault:true,
24647 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24648 handler: this.showNextMonth,
24650 preventDefault:true,
24654 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24656 this.monthPicker = this.el.down('div.x-date-mp');
24657 this.monthPicker.enableDisplayMode('block');
24659 var kn = new Roo.KeyNav(this.eventEl, {
24660 "left" : function(e){
24662 this.showPrevMonth() :
24663 this.update(this.activeDate.add("d", -1));
24666 "right" : function(e){
24668 this.showNextMonth() :
24669 this.update(this.activeDate.add("d", 1));
24672 "up" : function(e){
24674 this.showNextYear() :
24675 this.update(this.activeDate.add("d", -7));
24678 "down" : function(e){
24680 this.showPrevYear() :
24681 this.update(this.activeDate.add("d", 7));
24684 "pageUp" : function(e){
24685 this.showNextMonth();
24688 "pageDown" : function(e){
24689 this.showPrevMonth();
24692 "enter" : function(e){
24693 e.stopPropagation();
24700 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24702 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24704 this.el.unselectable();
24706 this.cells = this.el.select("table.x-date-inner tbody td");
24707 this.textNodes = this.el.query("table.x-date-inner tbody span");
24709 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24711 tooltip: this.monthYearText
24714 this.mbtn.on('click', this.showMonthPicker, this);
24715 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24718 var today = (new Date()).dateFormat(this.format);
24720 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24721 if (this.showClear) {
24722 baseTb.add( new Roo.Toolbar.Fill());
24725 text: String.format(this.todayText, today),
24726 tooltip: String.format(this.todayTip, today),
24727 handler: this.selectToday,
24731 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24734 if (this.showClear) {
24736 baseTb.add( new Roo.Toolbar.Fill());
24739 cls: 'x-btn-icon x-btn-clear',
24740 handler: function() {
24742 this.fireEvent("select", this, '');
24752 this.update(this.value);
24755 createMonthPicker : function(){
24756 if(!this.monthPicker.dom.firstChild){
24757 var buf = ['<table border="0" cellspacing="0">'];
24758 for(var i = 0; i < 6; i++){
24760 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24761 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24763 '<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>' :
24764 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24768 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24770 '</button><button type="button" class="x-date-mp-cancel">',
24772 '</button></td></tr>',
24775 this.monthPicker.update(buf.join(''));
24776 this.monthPicker.on('click', this.onMonthClick, this);
24777 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24779 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24780 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24782 this.mpMonths.each(function(m, a, i){
24785 m.dom.xmonth = 5 + Math.round(i * .5);
24787 m.dom.xmonth = Math.round((i-1) * .5);
24793 showMonthPicker : function(){
24794 this.createMonthPicker();
24795 var size = this.el.getSize();
24796 this.monthPicker.setSize(size);
24797 this.monthPicker.child('table').setSize(size);
24799 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24800 this.updateMPMonth(this.mpSelMonth);
24801 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24802 this.updateMPYear(this.mpSelYear);
24804 this.monthPicker.slideIn('t', {duration:.2});
24807 updateMPYear : function(y){
24809 var ys = this.mpYears.elements;
24810 for(var i = 1; i <= 10; i++){
24811 var td = ys[i-1], y2;
24813 y2 = y + Math.round(i * .5);
24814 td.firstChild.innerHTML = y2;
24817 y2 = y - (5-Math.round(i * .5));
24818 td.firstChild.innerHTML = y2;
24821 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24825 updateMPMonth : function(sm){
24826 this.mpMonths.each(function(m, a, i){
24827 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24831 selectMPMonth: function(m){
24835 onMonthClick : function(e, t){
24837 var el = new Roo.Element(t), pn;
24838 if(el.is('button.x-date-mp-cancel')){
24839 this.hideMonthPicker();
24841 else if(el.is('button.x-date-mp-ok')){
24842 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24843 this.hideMonthPicker();
24845 else if(pn = el.up('td.x-date-mp-month', 2)){
24846 this.mpMonths.removeClass('x-date-mp-sel');
24847 pn.addClass('x-date-mp-sel');
24848 this.mpSelMonth = pn.dom.xmonth;
24850 else if(pn = el.up('td.x-date-mp-year', 2)){
24851 this.mpYears.removeClass('x-date-mp-sel');
24852 pn.addClass('x-date-mp-sel');
24853 this.mpSelYear = pn.dom.xyear;
24855 else if(el.is('a.x-date-mp-prev')){
24856 this.updateMPYear(this.mpyear-10);
24858 else if(el.is('a.x-date-mp-next')){
24859 this.updateMPYear(this.mpyear+10);
24863 onMonthDblClick : function(e, t){
24865 var el = new Roo.Element(t), pn;
24866 if(pn = el.up('td.x-date-mp-month', 2)){
24867 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24868 this.hideMonthPicker();
24870 else if(pn = el.up('td.x-date-mp-year', 2)){
24871 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24872 this.hideMonthPicker();
24876 hideMonthPicker : function(disableAnim){
24877 if(this.monthPicker){
24878 if(disableAnim === true){
24879 this.monthPicker.hide();
24881 this.monthPicker.slideOut('t', {duration:.2});
24887 showPrevMonth : function(e){
24888 this.update(this.activeDate.add("mo", -1));
24892 showNextMonth : function(e){
24893 this.update(this.activeDate.add("mo", 1));
24897 showPrevYear : function(){
24898 this.update(this.activeDate.add("y", -1));
24902 showNextYear : function(){
24903 this.update(this.activeDate.add("y", 1));
24907 handleMouseWheel : function(e){
24908 var delta = e.getWheelDelta();
24910 this.showPrevMonth();
24912 } else if(delta < 0){
24913 this.showNextMonth();
24919 handleDateClick : function(e, t){
24921 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24922 this.setValue(new Date(t.dateValue));
24923 this.fireEvent("select", this, this.value);
24928 selectToday : function(){
24929 this.setValue(new Date().clearTime());
24930 this.fireEvent("select", this, this.value);
24934 update : function(date){
24935 var vd = this.activeDate;
24936 this.activeDate = date;
24938 var t = date.getTime();
24939 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24940 this.cells.removeClass("x-date-selected");
24941 this.cells.each(function(c){
24942 if(c.dom.firstChild.dateValue == t){
24943 c.addClass("x-date-selected");
24944 setTimeout(function(){
24945 try{c.dom.firstChild.focus();}catch(e){}
24953 var days = date.getDaysInMonth();
24954 var firstOfMonth = date.getFirstDateOfMonth();
24955 var startingPos = firstOfMonth.getDay()-this.startDay;
24957 if(startingPos <= this.startDay){
24961 var pm = date.add("mo", -1);
24962 var prevStart = pm.getDaysInMonth()-startingPos;
24964 var cells = this.cells.elements;
24965 var textEls = this.textNodes;
24966 days += startingPos;
24968 // convert everything to numbers so it's fast
24969 var day = 86400000;
24970 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24971 var today = new Date().clearTime().getTime();
24972 var sel = date.clearTime().getTime();
24973 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24974 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24975 var ddMatch = this.disabledDatesRE;
24976 var ddText = this.disabledDatesText;
24977 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24978 var ddaysText = this.disabledDaysText;
24979 var format = this.format;
24981 var setCellClass = function(cal, cell){
24983 var t = d.getTime();
24984 cell.firstChild.dateValue = t;
24986 cell.className += " x-date-today";
24987 cell.title = cal.todayText;
24990 cell.className += " x-date-selected";
24991 setTimeout(function(){
24992 try{cell.firstChild.focus();}catch(e){}
24997 cell.className = " x-date-disabled";
24998 cell.title = cal.minText;
25002 cell.className = " x-date-disabled";
25003 cell.title = cal.maxText;
25007 if(ddays.indexOf(d.getDay()) != -1){
25008 cell.title = ddaysText;
25009 cell.className = " x-date-disabled";
25012 if(ddMatch && format){
25013 var fvalue = d.dateFormat(format);
25014 if(ddMatch.test(fvalue)){
25015 cell.title = ddText.replace("%0", fvalue);
25016 cell.className = " x-date-disabled";
25022 for(; i < startingPos; i++) {
25023 textEls[i].innerHTML = (++prevStart);
25024 d.setDate(d.getDate()+1);
25025 cells[i].className = "x-date-prevday";
25026 setCellClass(this, cells[i]);
25028 for(; i < days; i++){
25029 intDay = i - startingPos + 1;
25030 textEls[i].innerHTML = (intDay);
25031 d.setDate(d.getDate()+1);
25032 cells[i].className = "x-date-active";
25033 setCellClass(this, cells[i]);
25036 for(; i < 42; i++) {
25037 textEls[i].innerHTML = (++extraDays);
25038 d.setDate(d.getDate()+1);
25039 cells[i].className = "x-date-nextday";
25040 setCellClass(this, cells[i]);
25043 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25045 if(!this.internalRender){
25046 var main = this.el.dom.firstChild;
25047 var w = main.offsetWidth;
25048 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25049 Roo.fly(main).setWidth(w);
25050 this.internalRender = true;
25051 // opera does not respect the auto grow header center column
25052 // then, after it gets a width opera refuses to recalculate
25053 // without a second pass
25054 if(Roo.isOpera && !this.secondPass){
25055 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25056 this.secondPass = true;
25057 this.update.defer(10, this, [date]);
25063 * Ext JS Library 1.1.1
25064 * Copyright(c) 2006-2007, Ext JS, LLC.
25066 * Originally Released Under LGPL - original licence link has changed is not relivant.
25069 * <script type="text/javascript">
25072 * @class Roo.TabPanel
25073 * @extends Roo.util.Observable
25074 * A lightweight tab container.
25078 // basic tabs 1, built from existing content
25079 var tabs = new Roo.TabPanel("tabs1");
25080 tabs.addTab("script", "View Script");
25081 tabs.addTab("markup", "View Markup");
25082 tabs.activate("script");
25084 // more advanced tabs, built from javascript
25085 var jtabs = new Roo.TabPanel("jtabs");
25086 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25088 // set up the UpdateManager
25089 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25090 var updater = tab2.getUpdateManager();
25091 updater.setDefaultUrl("ajax1.htm");
25092 tab2.on('activate', updater.refresh, updater, true);
25094 // Use setUrl for Ajax loading
25095 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25096 tab3.setUrl("ajax2.htm", null, true);
25099 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25102 jtabs.activate("jtabs-1");
25105 * Create a new TabPanel.
25106 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25107 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25109 Roo.TabPanel = function(container, config){
25111 * The container element for this TabPanel.
25112 * @type Roo.Element
25114 this.el = Roo.get(container, true);
25116 if(typeof config == "boolean"){
25117 this.tabPosition = config ? "bottom" : "top";
25119 Roo.apply(this, config);
25122 if(this.tabPosition == "bottom"){
25123 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25124 this.el.addClass("x-tabs-bottom");
25126 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25127 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25128 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25130 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25132 if(this.tabPosition != "bottom"){
25133 /** The body element that contains {@link Roo.TabPanelItem} bodies.
25134 * @type Roo.Element
25136 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25137 this.el.addClass("x-tabs-top");
25141 this.bodyEl.setStyle("position", "relative");
25143 this.active = null;
25144 this.activateDelegate = this.activate.createDelegate(this);
25149 * Fires when the active tab changes
25150 * @param {Roo.TabPanel} this
25151 * @param {Roo.TabPanelItem} activePanel The new active tab
25155 * @event beforetabchange
25156 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25157 * @param {Roo.TabPanel} this
25158 * @param {Object} e Set cancel to true on this object to cancel the tab change
25159 * @param {Roo.TabPanelItem} tab The tab being changed to
25161 "beforetabchange" : true
25164 Roo.EventManager.onWindowResize(this.onResize, this);
25165 this.cpad = this.el.getPadding("lr");
25166 this.hiddenCount = 0;
25168 Roo.TabPanel.superclass.constructor.call(this);
25171 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25173 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25175 tabPosition : "top",
25177 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25179 currentTabWidth : 0,
25181 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25185 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25189 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25191 preferredTabWidth : 175,
25193 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25195 resizeTabs : false,
25197 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25199 monitorResize : true,
25202 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25203 * @param {String} id The id of the div to use <b>or create</b>
25204 * @param {String} text The text for the tab
25205 * @param {String} content (optional) Content to put in the TabPanelItem body
25206 * @param {Boolean} closable (optional) True to create a close icon on the tab
25207 * @return {Roo.TabPanelItem} The created TabPanelItem
25209 addTab : function(id, text, content, closable){
25210 var item = new Roo.TabPanelItem(this, id, text, closable);
25211 this.addTabItem(item);
25213 item.setContent(content);
25219 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25220 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25221 * @return {Roo.TabPanelItem}
25223 getTab : function(id){
25224 return this.items[id];
25228 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25229 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25231 hideTab : function(id){
25232 var t = this.items[id];
25235 this.hiddenCount++;
25236 this.autoSizeTabs();
25241 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25242 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25244 unhideTab : function(id){
25245 var t = this.items[id];
25247 t.setHidden(false);
25248 this.hiddenCount--;
25249 this.autoSizeTabs();
25254 * Adds an existing {@link Roo.TabPanelItem}.
25255 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25257 addTabItem : function(item){
25258 this.items[item.id] = item;
25259 this.items.push(item);
25260 if(this.resizeTabs){
25261 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25262 this.autoSizeTabs();
25269 * Removes a {@link Roo.TabPanelItem}.
25270 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25272 removeTab : function(id){
25273 var items = this.items;
25274 var tab = items[id];
25275 if(!tab) { return; }
25276 var index = items.indexOf(tab);
25277 if(this.active == tab && items.length > 1){
25278 var newTab = this.getNextAvailable(index);
25283 this.stripEl.dom.removeChild(tab.pnode.dom);
25284 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25285 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25287 items.splice(index, 1);
25288 delete this.items[tab.id];
25289 tab.fireEvent("close", tab);
25290 tab.purgeListeners();
25291 this.autoSizeTabs();
25294 getNextAvailable : function(start){
25295 var items = this.items;
25297 // look for a next tab that will slide over to
25298 // replace the one being removed
25299 while(index < items.length){
25300 var item = items[++index];
25301 if(item && !item.isHidden()){
25305 // if one isn't found select the previous tab (on the left)
25308 var item = items[--index];
25309 if(item && !item.isHidden()){
25317 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25318 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25320 disableTab : function(id){
25321 var tab = this.items[id];
25322 if(tab && this.active != tab){
25328 * Enables a {@link Roo.TabPanelItem} that is disabled.
25329 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25331 enableTab : function(id){
25332 var tab = this.items[id];
25337 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25338 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25339 * @return {Roo.TabPanelItem} The TabPanelItem.
25341 activate : function(id){
25342 var tab = this.items[id];
25346 if(tab == this.active || tab.disabled){
25350 this.fireEvent("beforetabchange", this, e, tab);
25351 if(e.cancel !== true && !tab.disabled){
25353 this.active.hide();
25355 this.active = this.items[id];
25356 this.active.show();
25357 this.fireEvent("tabchange", this, this.active);
25363 * Gets the active {@link Roo.TabPanelItem}.
25364 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25366 getActiveTab : function(){
25367 return this.active;
25371 * Updates the tab body element to fit the height of the container element
25372 * for overflow scrolling
25373 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25375 syncHeight : function(targetHeight){
25376 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25377 var bm = this.bodyEl.getMargins();
25378 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25379 this.bodyEl.setHeight(newHeight);
25383 onResize : function(){
25384 if(this.monitorResize){
25385 this.autoSizeTabs();
25390 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25392 beginUpdate : function(){
25393 this.updating = true;
25397 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25399 endUpdate : function(){
25400 this.updating = false;
25401 this.autoSizeTabs();
25405 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25407 autoSizeTabs : function(){
25408 var count = this.items.length;
25409 var vcount = count - this.hiddenCount;
25410 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25411 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25412 var availWidth = Math.floor(w / vcount);
25413 var b = this.stripBody;
25414 if(b.getWidth() > w){
25415 var tabs = this.items;
25416 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25417 if(availWidth < this.minTabWidth){
25418 /*if(!this.sleft){ // incomplete scrolling code
25419 this.createScrollButtons();
25422 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25425 if(this.currentTabWidth < this.preferredTabWidth){
25426 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25432 * Returns the number of tabs in this TabPanel.
25435 getCount : function(){
25436 return this.items.length;
25440 * Resizes all the tabs to the passed width
25441 * @param {Number} The new width
25443 setTabWidth : function(width){
25444 this.currentTabWidth = width;
25445 for(var i = 0, len = this.items.length; i < len; i++) {
25446 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25451 * Destroys this TabPanel
25452 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25454 destroy : function(removeEl){
25455 Roo.EventManager.removeResizeListener(this.onResize, this);
25456 for(var i = 0, len = this.items.length; i < len; i++){
25457 this.items[i].purgeListeners();
25459 if(removeEl === true){
25460 this.el.update("");
25467 * @class Roo.TabPanelItem
25468 * @extends Roo.util.Observable
25469 * Represents an individual item (tab plus body) in a TabPanel.
25470 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25471 * @param {String} id The id of this TabPanelItem
25472 * @param {String} text The text for the tab of this TabPanelItem
25473 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25475 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25477 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25478 * @type Roo.TabPanel
25480 this.tabPanel = tabPanel;
25482 * The id for this TabPanelItem
25487 this.disabled = false;
25491 this.loaded = false;
25492 this.closable = closable;
25495 * The body element for this TabPanelItem.
25496 * @type Roo.Element
25498 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25499 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25500 this.bodyEl.setStyle("display", "block");
25501 this.bodyEl.setStyle("zoom", "1");
25504 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25506 this.el = Roo.get(els.el, true);
25507 this.inner = Roo.get(els.inner, true);
25508 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25509 this.pnode = Roo.get(els.el.parentNode, true);
25510 this.el.on("mousedown", this.onTabMouseDown, this);
25511 this.el.on("click", this.onTabClick, this);
25514 var c = Roo.get(els.close, true);
25515 c.dom.title = this.closeText;
25516 c.addClassOnOver("close-over");
25517 c.on("click", this.closeClick, this);
25523 * Fires when this tab becomes the active tab.
25524 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25525 * @param {Roo.TabPanelItem} this
25529 * @event beforeclose
25530 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25531 * @param {Roo.TabPanelItem} this
25532 * @param {Object} e Set cancel to true on this object to cancel the close.
25534 "beforeclose": true,
25537 * Fires when this tab is closed.
25538 * @param {Roo.TabPanelItem} this
25542 * @event deactivate
25543 * Fires when this tab is no longer the active tab.
25544 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25545 * @param {Roo.TabPanelItem} this
25547 "deactivate" : true
25549 this.hidden = false;
25551 Roo.TabPanelItem.superclass.constructor.call(this);
25554 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25555 purgeListeners : function(){
25556 Roo.util.Observable.prototype.purgeListeners.call(this);
25557 this.el.removeAllListeners();
25560 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25563 this.pnode.addClass("on");
25566 this.tabPanel.stripWrap.repaint();
25568 this.fireEvent("activate", this.tabPanel, this);
25572 * Returns true if this tab is the active tab.
25573 * @return {Boolean}
25575 isActive : function(){
25576 return this.tabPanel.getActiveTab() == this;
25580 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25583 this.pnode.removeClass("on");
25585 this.fireEvent("deactivate", this.tabPanel, this);
25588 hideAction : function(){
25589 this.bodyEl.hide();
25590 this.bodyEl.setStyle("position", "absolute");
25591 this.bodyEl.setLeft("-20000px");
25592 this.bodyEl.setTop("-20000px");
25595 showAction : function(){
25596 this.bodyEl.setStyle("position", "relative");
25597 this.bodyEl.setTop("");
25598 this.bodyEl.setLeft("");
25599 this.bodyEl.show();
25603 * Set the tooltip for the tab.
25604 * @param {String} tooltip The tab's tooltip
25606 setTooltip : function(text){
25607 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25608 this.textEl.dom.qtip = text;
25609 this.textEl.dom.removeAttribute('title');
25611 this.textEl.dom.title = text;
25615 onTabClick : function(e){
25616 e.preventDefault();
25617 this.tabPanel.activate(this.id);
25620 onTabMouseDown : function(e){
25621 e.preventDefault();
25622 this.tabPanel.activate(this.id);
25625 getWidth : function(){
25626 return this.inner.getWidth();
25629 setWidth : function(width){
25630 var iwidth = width - this.pnode.getPadding("lr");
25631 this.inner.setWidth(iwidth);
25632 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25633 this.pnode.setWidth(width);
25637 * Show or hide the tab
25638 * @param {Boolean} hidden True to hide or false to show.
25640 setHidden : function(hidden){
25641 this.hidden = hidden;
25642 this.pnode.setStyle("display", hidden ? "none" : "");
25646 * Returns true if this tab is "hidden"
25647 * @return {Boolean}
25649 isHidden : function(){
25650 return this.hidden;
25654 * Returns the text for this tab
25657 getText : function(){
25661 autoSize : function(){
25662 //this.el.beginMeasure();
25663 this.textEl.setWidth(1);
25664 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25665 //this.el.endMeasure();
25669 * Sets the text for the tab (Note: this also sets the tooltip text)
25670 * @param {String} text The tab's text and tooltip
25672 setText : function(text){
25674 this.textEl.update(text);
25675 this.setTooltip(text);
25676 if(!this.tabPanel.resizeTabs){
25681 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25683 activate : function(){
25684 this.tabPanel.activate(this.id);
25688 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25690 disable : function(){
25691 if(this.tabPanel.active != this){
25692 this.disabled = true;
25693 this.pnode.addClass("disabled");
25698 * Enables this TabPanelItem if it was previously disabled.
25700 enable : function(){
25701 this.disabled = false;
25702 this.pnode.removeClass("disabled");
25706 * Sets the content for this TabPanelItem.
25707 * @param {String} content The content
25708 * @param {Boolean} loadScripts true to look for and load scripts
25710 setContent : function(content, loadScripts){
25711 this.bodyEl.update(content, loadScripts);
25715 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25716 * @return {Roo.UpdateManager} The UpdateManager
25718 getUpdateManager : function(){
25719 return this.bodyEl.getUpdateManager();
25723 * Set a URL to be used to load the content for this TabPanelItem.
25724 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25725 * @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)
25726 * @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)
25727 * @return {Roo.UpdateManager} The UpdateManager
25729 setUrl : function(url, params, loadOnce){
25730 if(this.refreshDelegate){
25731 this.un('activate', this.refreshDelegate);
25733 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25734 this.on("activate", this.refreshDelegate);
25735 return this.bodyEl.getUpdateManager();
25739 _handleRefresh : function(url, params, loadOnce){
25740 if(!loadOnce || !this.loaded){
25741 var updater = this.bodyEl.getUpdateManager();
25742 updater.update(url, params, this._setLoaded.createDelegate(this));
25747 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25748 * Will fail silently if the setUrl method has not been called.
25749 * This does not activate the panel, just updates its content.
25751 refresh : function(){
25752 if(this.refreshDelegate){
25753 this.loaded = false;
25754 this.refreshDelegate();
25759 _setLoaded : function(){
25760 this.loaded = true;
25764 closeClick : function(e){
25767 this.fireEvent("beforeclose", this, o);
25768 if(o.cancel !== true){
25769 this.tabPanel.removeTab(this.id);
25773 * The text displayed in the tooltip for the close icon.
25776 closeText : "Close this tab"
25780 Roo.TabPanel.prototype.createStrip = function(container){
25781 var strip = document.createElement("div");
25782 strip.className = "x-tabs-wrap";
25783 container.appendChild(strip);
25787 Roo.TabPanel.prototype.createStripList = function(strip){
25788 // div wrapper for retard IE
25789 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>';
25790 return strip.firstChild.firstChild.firstChild.firstChild;
25793 Roo.TabPanel.prototype.createBody = function(container){
25794 var body = document.createElement("div");
25795 Roo.id(body, "tab-body");
25796 Roo.fly(body).addClass("x-tabs-body");
25797 container.appendChild(body);
25801 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25802 var body = Roo.getDom(id);
25804 body = document.createElement("div");
25807 Roo.fly(body).addClass("x-tabs-item-body");
25808 bodyEl.insertBefore(body, bodyEl.firstChild);
25812 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25813 var td = document.createElement("td");
25814 stripEl.appendChild(td);
25816 td.className = "x-tabs-closable";
25817 if(!this.closeTpl){
25818 this.closeTpl = new Roo.Template(
25819 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25820 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25821 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25824 var el = this.closeTpl.overwrite(td, {"text": text});
25825 var close = el.getElementsByTagName("div")[0];
25826 var inner = el.getElementsByTagName("em")[0];
25827 return {"el": el, "close": close, "inner": inner};
25830 this.tabTpl = new Roo.Template(
25831 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25832 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25835 var el = this.tabTpl.overwrite(td, {"text": text});
25836 var inner = el.getElementsByTagName("em")[0];
25837 return {"el": el, "inner": inner};
25841 * Ext JS Library 1.1.1
25842 * Copyright(c) 2006-2007, Ext JS, LLC.
25844 * Originally Released Under LGPL - original licence link has changed is not relivant.
25847 * <script type="text/javascript">
25851 * @class Roo.Button
25852 * @extends Roo.util.Observable
25853 * Simple Button class
25854 * @cfg {String} text The button text
25855 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25856 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25857 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25858 * @cfg {Object} scope The scope of the handler
25859 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25860 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25861 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25862 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25863 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25864 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25865 applies if enableToggle = true)
25866 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25867 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25868 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25870 * Create a new button
25871 * @param {Object} config The config object
25873 Roo.Button = function(renderTo, config)
25877 renderTo = config.renderTo || false;
25880 Roo.apply(this, config);
25884 * Fires when this button is clicked
25885 * @param {Button} this
25886 * @param {EventObject} e The click event
25891 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25892 * @param {Button} this
25893 * @param {Boolean} pressed
25898 * Fires when the mouse hovers over the button
25899 * @param {Button} this
25900 * @param {Event} e The event object
25902 'mouseover' : true,
25905 * Fires when the mouse exits the button
25906 * @param {Button} this
25907 * @param {Event} e The event object
25912 * Fires when the button is rendered
25913 * @param {Button} this
25918 this.menu = Roo.menu.MenuMgr.get(this.menu);
25920 // register listeners first!! - so render can be captured..
25921 Roo.util.Observable.call(this);
25923 this.render(renderTo);
25929 Roo.extend(Roo.Button, Roo.util.Observable, {
25935 * Read-only. True if this button is hidden
25940 * Read-only. True if this button is disabled
25945 * Read-only. True if this button is pressed (only if enableToggle = true)
25951 * @cfg {Number} tabIndex
25952 * The DOM tabIndex for this button (defaults to undefined)
25954 tabIndex : undefined,
25957 * @cfg {Boolean} enableToggle
25958 * True to enable pressed/not pressed toggling (defaults to false)
25960 enableToggle: false,
25962 * @cfg {Mixed} menu
25963 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25967 * @cfg {String} menuAlign
25968 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25970 menuAlign : "tl-bl?",
25973 * @cfg {String} iconCls
25974 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25976 iconCls : undefined,
25978 * @cfg {String} type
25979 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25984 menuClassTarget: 'tr',
25987 * @cfg {String} clickEvent
25988 * The type of event to map to the button's event handler (defaults to 'click')
25990 clickEvent : 'click',
25993 * @cfg {Boolean} handleMouseEvents
25994 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25996 handleMouseEvents : true,
25999 * @cfg {String} tooltipType
26000 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26002 tooltipType : 'qtip',
26005 * @cfg {String} cls
26006 * A CSS class to apply to the button's main element.
26010 * @cfg {Roo.Template} template (Optional)
26011 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26012 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26013 * require code modifications if required elements (e.g. a button) aren't present.
26017 render : function(renderTo){
26019 if(this.hideParent){
26020 this.parentEl = Roo.get(renderTo);
26022 if(!this.dhconfig){
26023 if(!this.template){
26024 if(!Roo.Button.buttonTemplate){
26025 // hideous table template
26026 Roo.Button.buttonTemplate = new Roo.Template(
26027 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26028 '<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>',
26029 "</tr></tbody></table>");
26031 this.template = Roo.Button.buttonTemplate;
26033 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26034 var btnEl = btn.child("button:first");
26035 btnEl.on('focus', this.onFocus, this);
26036 btnEl.on('blur', this.onBlur, this);
26038 btn.addClass(this.cls);
26041 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26044 btnEl.addClass(this.iconCls);
26046 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26049 if(this.tabIndex !== undefined){
26050 btnEl.dom.tabIndex = this.tabIndex;
26053 if(typeof this.tooltip == 'object'){
26054 Roo.QuickTips.tips(Roo.apply({
26058 btnEl.dom[this.tooltipType] = this.tooltip;
26062 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26066 this.el.dom.id = this.el.id = this.id;
26069 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26070 this.menu.on("show", this.onMenuShow, this);
26071 this.menu.on("hide", this.onMenuHide, this);
26073 btn.addClass("x-btn");
26074 if(Roo.isIE && !Roo.isIE7){
26075 this.autoWidth.defer(1, this);
26079 if(this.handleMouseEvents){
26080 btn.on("mouseover", this.onMouseOver, this);
26081 btn.on("mouseout", this.onMouseOut, this);
26082 btn.on("mousedown", this.onMouseDown, this);
26084 btn.on(this.clickEvent, this.onClick, this);
26085 //btn.on("mouseup", this.onMouseUp, this);
26092 Roo.ButtonToggleMgr.register(this);
26094 this.el.addClass("x-btn-pressed");
26097 var repeater = new Roo.util.ClickRepeater(btn,
26098 typeof this.repeat == "object" ? this.repeat : {}
26100 repeater.on("click", this.onClick, this);
26103 this.fireEvent('render', this);
26107 * Returns the button's underlying element
26108 * @return {Roo.Element} The element
26110 getEl : function(){
26115 * Destroys this Button and removes any listeners.
26117 destroy : function(){
26118 Roo.ButtonToggleMgr.unregister(this);
26119 this.el.removeAllListeners();
26120 this.purgeListeners();
26125 autoWidth : function(){
26127 this.el.setWidth("auto");
26128 if(Roo.isIE7 && Roo.isStrict){
26129 var ib = this.el.child('button');
26130 if(ib && ib.getWidth() > 20){
26132 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26137 this.el.beginMeasure();
26139 if(this.el.getWidth() < this.minWidth){
26140 this.el.setWidth(this.minWidth);
26143 this.el.endMeasure();
26150 * Assigns this button's click handler
26151 * @param {Function} handler The function to call when the button is clicked
26152 * @param {Object} scope (optional) Scope for the function passed in
26154 setHandler : function(handler, scope){
26155 this.handler = handler;
26156 this.scope = scope;
26160 * Sets this button's text
26161 * @param {String} text The button text
26163 setText : function(text){
26166 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26172 * Gets the text for this button
26173 * @return {String} The button text
26175 getText : function(){
26183 this.hidden = false;
26185 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26193 this.hidden = true;
26195 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26200 * Convenience function for boolean show/hide
26201 * @param {Boolean} visible True to show, false to hide
26203 setVisible: function(visible){
26212 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26213 * @param {Boolean} state (optional) Force a particular state
26215 toggle : function(state){
26216 state = state === undefined ? !this.pressed : state;
26217 if(state != this.pressed){
26219 this.el.addClass("x-btn-pressed");
26220 this.pressed = true;
26221 this.fireEvent("toggle", this, true);
26223 this.el.removeClass("x-btn-pressed");
26224 this.pressed = false;
26225 this.fireEvent("toggle", this, false);
26227 if(this.toggleHandler){
26228 this.toggleHandler.call(this.scope || this, this, state);
26236 focus : function(){
26237 this.el.child('button:first').focus();
26241 * Disable this button
26243 disable : function(){
26245 this.el.addClass("x-btn-disabled");
26247 this.disabled = true;
26251 * Enable this button
26253 enable : function(){
26255 this.el.removeClass("x-btn-disabled");
26257 this.disabled = false;
26261 * Convenience function for boolean enable/disable
26262 * @param {Boolean} enabled True to enable, false to disable
26264 setDisabled : function(v){
26265 this[v !== true ? "enable" : "disable"]();
26269 onClick : function(e){
26271 e.preventDefault();
26276 if(!this.disabled){
26277 if(this.enableToggle){
26280 if(this.menu && !this.menu.isVisible()){
26281 this.menu.show(this.el, this.menuAlign);
26283 this.fireEvent("click", this, e);
26285 this.el.removeClass("x-btn-over");
26286 this.handler.call(this.scope || this, this, e);
26291 onMouseOver : function(e){
26292 if(!this.disabled){
26293 this.el.addClass("x-btn-over");
26294 this.fireEvent('mouseover', this, e);
26298 onMouseOut : function(e){
26299 if(!e.within(this.el, true)){
26300 this.el.removeClass("x-btn-over");
26301 this.fireEvent('mouseout', this, e);
26305 onFocus : function(e){
26306 if(!this.disabled){
26307 this.el.addClass("x-btn-focus");
26311 onBlur : function(e){
26312 this.el.removeClass("x-btn-focus");
26315 onMouseDown : function(e){
26316 if(!this.disabled && e.button == 0){
26317 this.el.addClass("x-btn-click");
26318 Roo.get(document).on('mouseup', this.onMouseUp, this);
26322 onMouseUp : function(e){
26324 this.el.removeClass("x-btn-click");
26325 Roo.get(document).un('mouseup', this.onMouseUp, this);
26329 onMenuShow : function(e){
26330 this.el.addClass("x-btn-menu-active");
26333 onMenuHide : function(e){
26334 this.el.removeClass("x-btn-menu-active");
26338 // Private utility class used by Button
26339 Roo.ButtonToggleMgr = function(){
26342 function toggleGroup(btn, state){
26344 var g = groups[btn.toggleGroup];
26345 for(var i = 0, l = g.length; i < l; i++){
26347 g[i].toggle(false);
26354 register : function(btn){
26355 if(!btn.toggleGroup){
26358 var g = groups[btn.toggleGroup];
26360 g = groups[btn.toggleGroup] = [];
26363 btn.on("toggle", toggleGroup);
26366 unregister : function(btn){
26367 if(!btn.toggleGroup){
26370 var g = groups[btn.toggleGroup];
26373 btn.un("toggle", toggleGroup);
26379 * Ext JS Library 1.1.1
26380 * Copyright(c) 2006-2007, Ext JS, LLC.
26382 * Originally Released Under LGPL - original licence link has changed is not relivant.
26385 * <script type="text/javascript">
26389 * @class Roo.SplitButton
26390 * @extends Roo.Button
26391 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26392 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26393 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26394 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26395 * @cfg {String} arrowTooltip The title attribute of the arrow
26397 * Create a new menu button
26398 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26399 * @param {Object} config The config object
26401 Roo.SplitButton = function(renderTo, config){
26402 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26404 * @event arrowclick
26405 * Fires when this button's arrow is clicked
26406 * @param {SplitButton} this
26407 * @param {EventObject} e The click event
26409 this.addEvents({"arrowclick":true});
26412 Roo.extend(Roo.SplitButton, Roo.Button, {
26413 render : function(renderTo){
26414 // this is one sweet looking template!
26415 var tpl = new Roo.Template(
26416 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26417 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26418 '<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>',
26419 "</tbody></table></td><td>",
26420 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26421 '<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>',
26422 "</tbody></table></td></tr></table>"
26424 var btn = tpl.append(renderTo, [this.text, this.type], true);
26425 var btnEl = btn.child("button");
26427 btn.addClass(this.cls);
26430 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26433 btnEl.addClass(this.iconCls);
26435 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26439 if(this.handleMouseEvents){
26440 btn.on("mouseover", this.onMouseOver, this);
26441 btn.on("mouseout", this.onMouseOut, this);
26442 btn.on("mousedown", this.onMouseDown, this);
26443 btn.on("mouseup", this.onMouseUp, this);
26445 btn.on(this.clickEvent, this.onClick, this);
26447 if(typeof this.tooltip == 'object'){
26448 Roo.QuickTips.tips(Roo.apply({
26452 btnEl.dom[this.tooltipType] = this.tooltip;
26455 if(this.arrowTooltip){
26456 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26465 this.el.addClass("x-btn-pressed");
26467 if(Roo.isIE && !Roo.isIE7){
26468 this.autoWidth.defer(1, this);
26473 this.menu.on("show", this.onMenuShow, this);
26474 this.menu.on("hide", this.onMenuHide, this);
26476 this.fireEvent('render', this);
26480 autoWidth : function(){
26482 var tbl = this.el.child("table:first");
26483 var tbl2 = this.el.child("table:last");
26484 this.el.setWidth("auto");
26485 tbl.setWidth("auto");
26486 if(Roo.isIE7 && Roo.isStrict){
26487 var ib = this.el.child('button:first');
26488 if(ib && ib.getWidth() > 20){
26490 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26495 this.el.beginMeasure();
26497 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26498 tbl.setWidth(this.minWidth-tbl2.getWidth());
26501 this.el.endMeasure();
26504 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26508 * Sets this button's click handler
26509 * @param {Function} handler The function to call when the button is clicked
26510 * @param {Object} scope (optional) Scope for the function passed above
26512 setHandler : function(handler, scope){
26513 this.handler = handler;
26514 this.scope = scope;
26518 * Sets this button's arrow click handler
26519 * @param {Function} handler The function to call when the arrow is clicked
26520 * @param {Object} scope (optional) Scope for the function passed above
26522 setArrowHandler : function(handler, scope){
26523 this.arrowHandler = handler;
26524 this.scope = scope;
26530 focus : function(){
26532 this.el.child("button:first").focus();
26537 onClick : function(e){
26538 e.preventDefault();
26539 if(!this.disabled){
26540 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26541 if(this.menu && !this.menu.isVisible()){
26542 this.menu.show(this.el, this.menuAlign);
26544 this.fireEvent("arrowclick", this, e);
26545 if(this.arrowHandler){
26546 this.arrowHandler.call(this.scope || this, this, e);
26549 this.fireEvent("click", this, e);
26551 this.handler.call(this.scope || this, this, e);
26557 onMouseDown : function(e){
26558 if(!this.disabled){
26559 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26563 onMouseUp : function(e){
26564 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26569 // backwards compat
26570 Roo.MenuButton = Roo.SplitButton;/*
26572 * Ext JS Library 1.1.1
26573 * Copyright(c) 2006-2007, Ext JS, LLC.
26575 * Originally Released Under LGPL - original licence link has changed is not relivant.
26578 * <script type="text/javascript">
26582 * @class Roo.Toolbar
26583 * Basic Toolbar class.
26585 * Creates a new Toolbar
26586 * @param {Object} config The config object
26588 Roo.Toolbar = function(container, buttons, config)
26590 /// old consturctor format still supported..
26591 if(container instanceof Array){ // omit the container for later rendering
26592 buttons = container;
26596 if (typeof(container) == 'object' && container.xtype) {
26597 config = container;
26598 container = config.container;
26599 buttons = config.buttons; // not really - use items!!
26602 if (config && config.items) {
26603 xitems = config.items;
26604 delete config.items;
26606 Roo.apply(this, config);
26607 this.buttons = buttons;
26610 this.render(container);
26612 Roo.each(xitems, function(b) {
26618 Roo.Toolbar.prototype = {
26620 * @cfg {Roo.data.Store} items
26621 * array of button configs or elements to add
26625 * @cfg {String/HTMLElement/Element} container
26626 * The id or element that will contain the toolbar
26629 render : function(ct){
26630 this.el = Roo.get(ct);
26632 this.el.addClass(this.cls);
26634 // using a table allows for vertical alignment
26635 // 100% width is needed by Safari...
26636 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26637 this.tr = this.el.child("tr", true);
26639 this.items = new Roo.util.MixedCollection(false, function(o){
26640 return o.id || ("item" + (++autoId));
26643 this.add.apply(this, this.buttons);
26644 delete this.buttons;
26649 * Adds element(s) to the toolbar -- this function takes a variable number of
26650 * arguments of mixed type and adds them to the toolbar.
26651 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26653 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26654 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26655 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26656 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26657 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26658 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26659 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26660 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26661 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26663 * @param {Mixed} arg2
26664 * @param {Mixed} etc.
26667 var a = arguments, l = a.length;
26668 for(var i = 0; i < l; i++){
26673 _add : function(el) {
26676 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26679 if (el.applyTo){ // some kind of form field
26680 return this.addField(el);
26682 if (el.render){ // some kind of Toolbar.Item
26683 return this.addItem(el);
26685 if (typeof el == "string"){ // string
26686 if(el == "separator" || el == "-"){
26687 return this.addSeparator();
26690 return this.addSpacer();
26693 return this.addFill();
26695 return this.addText(el);
26698 if(el.tagName){ // element
26699 return this.addElement(el);
26701 if(typeof el == "object"){ // must be button config?
26702 return this.addButton(el);
26704 // and now what?!?!
26710 * Add an Xtype element
26711 * @param {Object} xtype Xtype Object
26712 * @return {Object} created Object
26714 addxtype : function(e){
26715 return this.add(e);
26719 * Returns the Element for this toolbar.
26720 * @return {Roo.Element}
26722 getEl : function(){
26728 * @return {Roo.Toolbar.Item} The separator item
26730 addSeparator : function(){
26731 return this.addItem(new Roo.Toolbar.Separator());
26735 * Adds a spacer element
26736 * @return {Roo.Toolbar.Spacer} The spacer item
26738 addSpacer : function(){
26739 return this.addItem(new Roo.Toolbar.Spacer());
26743 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26744 * @return {Roo.Toolbar.Fill} The fill item
26746 addFill : function(){
26747 return this.addItem(new Roo.Toolbar.Fill());
26751 * Adds any standard HTML element to the toolbar
26752 * @param {String/HTMLElement/Element} el The element or id of the element to add
26753 * @return {Roo.Toolbar.Item} The element's item
26755 addElement : function(el){
26756 return this.addItem(new Roo.Toolbar.Item(el));
26759 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26760 * @type Roo.util.MixedCollection
26765 * Adds any Toolbar.Item or subclass
26766 * @param {Roo.Toolbar.Item} item
26767 * @return {Roo.Toolbar.Item} The item
26769 addItem : function(item){
26770 var td = this.nextBlock();
26772 this.items.add(item);
26777 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26778 * @param {Object/Array} config A button config or array of configs
26779 * @return {Roo.Toolbar.Button/Array}
26781 addButton : function(config){
26782 if(config instanceof Array){
26784 for(var i = 0, len = config.length; i < len; i++) {
26785 buttons.push(this.addButton(config[i]));
26790 if(!(config instanceof Roo.Toolbar.Button)){
26792 new Roo.Toolbar.SplitButton(config) :
26793 new Roo.Toolbar.Button(config);
26795 var td = this.nextBlock();
26802 * Adds text to the toolbar
26803 * @param {String} text The text to add
26804 * @return {Roo.Toolbar.Item} The element's item
26806 addText : function(text){
26807 return this.addItem(new Roo.Toolbar.TextItem(text));
26811 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26812 * @param {Number} index The index where the item is to be inserted
26813 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26814 * @return {Roo.Toolbar.Button/Item}
26816 insertButton : function(index, item){
26817 if(item instanceof Array){
26819 for(var i = 0, len = item.length; i < len; i++) {
26820 buttons.push(this.insertButton(index + i, item[i]));
26824 if (!(item instanceof Roo.Toolbar.Button)){
26825 item = new Roo.Toolbar.Button(item);
26827 var td = document.createElement("td");
26828 this.tr.insertBefore(td, this.tr.childNodes[index]);
26830 this.items.insert(index, item);
26835 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26836 * @param {Object} config
26837 * @return {Roo.Toolbar.Item} The element's item
26839 addDom : function(config, returnEl){
26840 var td = this.nextBlock();
26841 Roo.DomHelper.overwrite(td, config);
26842 var ti = new Roo.Toolbar.Item(td.firstChild);
26844 this.items.add(ti);
26849 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26850 * @type Roo.util.MixedCollection
26855 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26856 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26857 * @param {Roo.form.Field} field
26858 * @return {Roo.ToolbarItem}
26862 addField : function(field) {
26863 if (!this.fields) {
26865 this.fields = new Roo.util.MixedCollection(false, function(o){
26866 return o.id || ("item" + (++autoId));
26871 var td = this.nextBlock();
26873 var ti = new Roo.Toolbar.Item(td.firstChild);
26875 this.items.add(ti);
26876 this.fields.add(field);
26887 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26888 this.el.child('div').hide();
26896 this.el.child('div').show();
26900 nextBlock : function(){
26901 var td = document.createElement("td");
26902 this.tr.appendChild(td);
26907 destroy : function(){
26908 if(this.items){ // rendered?
26909 Roo.destroy.apply(Roo, this.items.items);
26911 if(this.fields){ // rendered?
26912 Roo.destroy.apply(Roo, this.fields.items);
26914 Roo.Element.uncache(this.el, this.tr);
26919 * @class Roo.Toolbar.Item
26920 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26922 * Creates a new Item
26923 * @param {HTMLElement} el
26925 Roo.Toolbar.Item = function(el){
26926 this.el = Roo.getDom(el);
26927 this.id = Roo.id(this.el);
26928 this.hidden = false;
26931 Roo.Toolbar.Item.prototype = {
26934 * Get this item's HTML Element
26935 * @return {HTMLElement}
26937 getEl : function(){
26942 render : function(td){
26944 td.appendChild(this.el);
26948 * Removes and destroys this item.
26950 destroy : function(){
26951 this.td.parentNode.removeChild(this.td);
26958 this.hidden = false;
26959 this.td.style.display = "";
26966 this.hidden = true;
26967 this.td.style.display = "none";
26971 * Convenience function for boolean show/hide.
26972 * @param {Boolean} visible true to show/false to hide
26974 setVisible: function(visible){
26983 * Try to focus this item.
26985 focus : function(){
26986 Roo.fly(this.el).focus();
26990 * Disables this item.
26992 disable : function(){
26993 Roo.fly(this.td).addClass("x-item-disabled");
26994 this.disabled = true;
26995 this.el.disabled = true;
26999 * Enables this item.
27001 enable : function(){
27002 Roo.fly(this.td).removeClass("x-item-disabled");
27003 this.disabled = false;
27004 this.el.disabled = false;
27010 * @class Roo.Toolbar.Separator
27011 * @extends Roo.Toolbar.Item
27012 * A simple toolbar separator class
27014 * Creates a new Separator
27016 Roo.Toolbar.Separator = function(){
27017 var s = document.createElement("span");
27018 s.className = "ytb-sep";
27019 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27021 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27022 enable:Roo.emptyFn,
27023 disable:Roo.emptyFn,
27028 * @class Roo.Toolbar.Spacer
27029 * @extends Roo.Toolbar.Item
27030 * A simple element that adds extra horizontal space to a toolbar.
27032 * Creates a new Spacer
27034 Roo.Toolbar.Spacer = function(){
27035 var s = document.createElement("div");
27036 s.className = "ytb-spacer";
27037 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27039 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27040 enable:Roo.emptyFn,
27041 disable:Roo.emptyFn,
27046 * @class Roo.Toolbar.Fill
27047 * @extends Roo.Toolbar.Spacer
27048 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27050 * Creates a new Spacer
27052 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27054 render : function(td){
27055 td.style.width = '100%';
27056 Roo.Toolbar.Fill.superclass.render.call(this, td);
27061 * @class Roo.Toolbar.TextItem
27062 * @extends Roo.Toolbar.Item
27063 * A simple class that renders text directly into a toolbar.
27065 * Creates a new TextItem
27066 * @param {String} text
27068 Roo.Toolbar.TextItem = function(text){
27069 if (typeof(text) == 'object') {
27072 var s = document.createElement("span");
27073 s.className = "ytb-text";
27074 s.innerHTML = text;
27075 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27077 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27078 enable:Roo.emptyFn,
27079 disable:Roo.emptyFn,
27084 * @class Roo.Toolbar.Button
27085 * @extends Roo.Button
27086 * A button that renders into a toolbar.
27088 * Creates a new Button
27089 * @param {Object} config A standard {@link Roo.Button} config object
27091 Roo.Toolbar.Button = function(config){
27092 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27094 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27095 render : function(td){
27097 Roo.Toolbar.Button.superclass.render.call(this, td);
27101 * Removes and destroys this button
27103 destroy : function(){
27104 Roo.Toolbar.Button.superclass.destroy.call(this);
27105 this.td.parentNode.removeChild(this.td);
27109 * Shows this button
27112 this.hidden = false;
27113 this.td.style.display = "";
27117 * Hides this button
27120 this.hidden = true;
27121 this.td.style.display = "none";
27125 * Disables this item
27127 disable : function(){
27128 Roo.fly(this.td).addClass("x-item-disabled");
27129 this.disabled = true;
27133 * Enables this item
27135 enable : function(){
27136 Roo.fly(this.td).removeClass("x-item-disabled");
27137 this.disabled = false;
27140 // backwards compat
27141 Roo.ToolbarButton = Roo.Toolbar.Button;
27144 * @class Roo.Toolbar.SplitButton
27145 * @extends Roo.SplitButton
27146 * A menu button that renders into a toolbar.
27148 * Creates a new SplitButton
27149 * @param {Object} config A standard {@link Roo.SplitButton} config object
27151 Roo.Toolbar.SplitButton = function(config){
27152 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27154 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27155 render : function(td){
27157 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27161 * Removes and destroys this button
27163 destroy : function(){
27164 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27165 this.td.parentNode.removeChild(this.td);
27169 * Shows this button
27172 this.hidden = false;
27173 this.td.style.display = "";
27177 * Hides this button
27180 this.hidden = true;
27181 this.td.style.display = "none";
27185 // backwards compat
27186 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27188 * Ext JS Library 1.1.1
27189 * Copyright(c) 2006-2007, Ext JS, LLC.
27191 * Originally Released Under LGPL - original licence link has changed is not relivant.
27194 * <script type="text/javascript">
27198 * @class Roo.PagingToolbar
27199 * @extends Roo.Toolbar
27200 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27202 * Create a new PagingToolbar
27203 * @param {Object} config The config object
27205 Roo.PagingToolbar = function(el, ds, config)
27207 // old args format still supported... - xtype is prefered..
27208 if (typeof(el) == 'object' && el.xtype) {
27209 // created from xtype...
27211 ds = el.dataSource;
27212 el = config.container;
27215 if (config.items) {
27216 items = config.items;
27220 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27223 this.renderButtons(this.el);
27226 // supprot items array.
27228 Roo.each(items, function(e) {
27229 this.add(Roo.factory(e));
27234 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27236 * @cfg {Roo.data.Store} dataSource
27237 * The underlying data store providing the paged data
27240 * @cfg {String/HTMLElement/Element} container
27241 * container The id or element that will contain the toolbar
27244 * @cfg {Boolean} displayInfo
27245 * True to display the displayMsg (defaults to false)
27248 * @cfg {Number} pageSize
27249 * The number of records to display per page (defaults to 20)
27253 * @cfg {String} displayMsg
27254 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27256 displayMsg : 'Displaying {0} - {1} of {2}',
27258 * @cfg {String} emptyMsg
27259 * The message to display when no records are found (defaults to "No data to display")
27261 emptyMsg : 'No data to display',
27263 * Customizable piece of the default paging text (defaults to "Page")
27266 beforePageText : "Page",
27268 * Customizable piece of the default paging text (defaults to "of %0")
27271 afterPageText : "of {0}",
27273 * Customizable piece of the default paging text (defaults to "First Page")
27276 firstText : "First Page",
27278 * Customizable piece of the default paging text (defaults to "Previous Page")
27281 prevText : "Previous Page",
27283 * Customizable piece of the default paging text (defaults to "Next Page")
27286 nextText : "Next Page",
27288 * Customizable piece of the default paging text (defaults to "Last Page")
27291 lastText : "Last Page",
27293 * Customizable piece of the default paging text (defaults to "Refresh")
27296 refreshText : "Refresh",
27299 renderButtons : function(el){
27300 Roo.PagingToolbar.superclass.render.call(this, el);
27301 this.first = this.addButton({
27302 tooltip: this.firstText,
27303 cls: "x-btn-icon x-grid-page-first",
27305 handler: this.onClick.createDelegate(this, ["first"])
27307 this.prev = this.addButton({
27308 tooltip: this.prevText,
27309 cls: "x-btn-icon x-grid-page-prev",
27311 handler: this.onClick.createDelegate(this, ["prev"])
27313 //this.addSeparator();
27314 this.add(this.beforePageText);
27315 this.field = Roo.get(this.addDom({
27320 cls: "x-grid-page-number"
27322 this.field.on("keydown", this.onPagingKeydown, this);
27323 this.field.on("focus", function(){this.dom.select();});
27324 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27325 this.field.setHeight(18);
27326 //this.addSeparator();
27327 this.next = this.addButton({
27328 tooltip: this.nextText,
27329 cls: "x-btn-icon x-grid-page-next",
27331 handler: this.onClick.createDelegate(this, ["next"])
27333 this.last = this.addButton({
27334 tooltip: this.lastText,
27335 cls: "x-btn-icon x-grid-page-last",
27337 handler: this.onClick.createDelegate(this, ["last"])
27339 //this.addSeparator();
27340 this.loading = this.addButton({
27341 tooltip: this.refreshText,
27342 cls: "x-btn-icon x-grid-loading",
27343 handler: this.onClick.createDelegate(this, ["refresh"])
27346 if(this.displayInfo){
27347 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27352 updateInfo : function(){
27353 if(this.displayEl){
27354 var count = this.ds.getCount();
27355 var msg = count == 0 ?
27359 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27361 this.displayEl.update(msg);
27366 onLoad : function(ds, r, o){
27367 this.cursor = o.params ? o.params.start : 0;
27368 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27370 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27371 this.field.dom.value = ap;
27372 this.first.setDisabled(ap == 1);
27373 this.prev.setDisabled(ap == 1);
27374 this.next.setDisabled(ap == ps);
27375 this.last.setDisabled(ap == ps);
27376 this.loading.enable();
27381 getPageData : function(){
27382 var total = this.ds.getTotalCount();
27385 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27386 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27391 onLoadError : function(){
27392 this.loading.enable();
27396 onPagingKeydown : function(e){
27397 var k = e.getKey();
27398 var d = this.getPageData();
27400 var v = this.field.dom.value, pageNum;
27401 if(!v || isNaN(pageNum = parseInt(v, 10))){
27402 this.field.dom.value = d.activePage;
27405 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27406 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27409 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))
27411 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27412 this.field.dom.value = pageNum;
27413 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27416 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27418 var v = this.field.dom.value, pageNum;
27419 var increment = (e.shiftKey) ? 10 : 1;
27420 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27422 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27423 this.field.dom.value = d.activePage;
27426 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27428 this.field.dom.value = parseInt(v, 10) + increment;
27429 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27430 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27437 beforeLoad : function(){
27439 this.loading.disable();
27444 onClick : function(which){
27448 ds.load({params:{start: 0, limit: this.pageSize}});
27451 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27454 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27457 var total = ds.getTotalCount();
27458 var extra = total % this.pageSize;
27459 var lastStart = extra ? (total - extra) : total-this.pageSize;
27460 ds.load({params:{start: lastStart, limit: this.pageSize}});
27463 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27469 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27470 * @param {Roo.data.Store} store The data store to unbind
27472 unbind : function(ds){
27473 ds.un("beforeload", this.beforeLoad, this);
27474 ds.un("load", this.onLoad, this);
27475 ds.un("loadexception", this.onLoadError, this);
27476 ds.un("remove", this.updateInfo, this);
27477 ds.un("add", this.updateInfo, this);
27478 this.ds = undefined;
27482 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27483 * @param {Roo.data.Store} store The data store to bind
27485 bind : function(ds){
27486 ds.on("beforeload", this.beforeLoad, this);
27487 ds.on("load", this.onLoad, this);
27488 ds.on("loadexception", this.onLoadError, this);
27489 ds.on("remove", this.updateInfo, this);
27490 ds.on("add", this.updateInfo, this);
27495 * Ext JS Library 1.1.1
27496 * Copyright(c) 2006-2007, Ext JS, LLC.
27498 * Originally Released Under LGPL - original licence link has changed is not relivant.
27501 * <script type="text/javascript">
27505 * @class Roo.Resizable
27506 * @extends Roo.util.Observable
27507 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27508 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27509 * 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
27510 * the element will be wrapped for you automatically.</p>
27511 * <p>Here is the list of valid resize handles:</p>
27514 ------ -------------------
27523 'hd' horizontal drag
27526 * <p>Here's an example showing the creation of a typical Resizable:</p>
27528 var resizer = new Roo.Resizable("element-id", {
27536 resizer.on("resize", myHandler);
27538 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27539 * resizer.east.setDisplayed(false);</p>
27540 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27541 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27542 * resize operation's new size (defaults to [0, 0])
27543 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27544 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27545 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27546 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27547 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27548 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27549 * @cfg {Number} width The width of the element in pixels (defaults to null)
27550 * @cfg {Number} height The height of the element in pixels (defaults to null)
27551 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27552 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27553 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27554 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27555 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27556 * in favor of the handles config option (defaults to false)
27557 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27558 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27559 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27560 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27561 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27562 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27563 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27564 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27565 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27566 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27567 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27569 * Create a new resizable component
27570 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27571 * @param {Object} config configuration options
27573 Roo.Resizable = function(el, config)
27575 this.el = Roo.get(el);
27577 if(config && config.wrap){
27578 config.resizeChild = this.el;
27579 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27580 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27581 this.el.setStyle("overflow", "hidden");
27582 this.el.setPositioning(config.resizeChild.getPositioning());
27583 config.resizeChild.clearPositioning();
27584 if(!config.width || !config.height){
27585 var csize = config.resizeChild.getSize();
27586 this.el.setSize(csize.width, csize.height);
27588 if(config.pinned && !config.adjustments){
27589 config.adjustments = "auto";
27593 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27594 this.proxy.unselectable();
27595 this.proxy.enableDisplayMode('block');
27597 Roo.apply(this, config);
27600 this.disableTrackOver = true;
27601 this.el.addClass("x-resizable-pinned");
27603 // if the element isn't positioned, make it relative
27604 var position = this.el.getStyle("position");
27605 if(position != "absolute" && position != "fixed"){
27606 this.el.setStyle("position", "relative");
27608 if(!this.handles){ // no handles passed, must be legacy style
27609 this.handles = 's,e,se';
27610 if(this.multiDirectional){
27611 this.handles += ',n,w';
27614 if(this.handles == "all"){
27615 this.handles = "n s e w ne nw se sw";
27617 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27618 var ps = Roo.Resizable.positions;
27619 for(var i = 0, len = hs.length; i < len; i++){
27620 if(hs[i] && ps[hs[i]]){
27621 var pos = ps[hs[i]];
27622 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27626 this.corner = this.southeast;
27628 // updateBox = the box can move..
27629 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27630 this.updateBox = true;
27633 this.activeHandle = null;
27635 if(this.resizeChild){
27636 if(typeof this.resizeChild == "boolean"){
27637 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27639 this.resizeChild = Roo.get(this.resizeChild, true);
27643 if(this.adjustments == "auto"){
27644 var rc = this.resizeChild;
27645 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27646 if(rc && (hw || hn)){
27647 rc.position("relative");
27648 rc.setLeft(hw ? hw.el.getWidth() : 0);
27649 rc.setTop(hn ? hn.el.getHeight() : 0);
27651 this.adjustments = [
27652 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27653 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27657 if(this.draggable){
27658 this.dd = this.dynamic ?
27659 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27660 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27666 * @event beforeresize
27667 * Fired before resize is allowed. Set enabled to false to cancel resize.
27668 * @param {Roo.Resizable} this
27669 * @param {Roo.EventObject} e The mousedown event
27671 "beforeresize" : true,
27674 * Fired after a resize.
27675 * @param {Roo.Resizable} this
27676 * @param {Number} width The new width
27677 * @param {Number} height The new height
27678 * @param {Roo.EventObject} e The mouseup event
27683 if(this.width !== null && this.height !== null){
27684 this.resizeTo(this.width, this.height);
27686 this.updateChildSize();
27689 this.el.dom.style.zoom = 1;
27691 Roo.Resizable.superclass.constructor.call(this);
27694 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27695 resizeChild : false,
27696 adjustments : [0, 0],
27706 multiDirectional : false,
27707 disableTrackOver : false,
27708 easing : 'easeOutStrong',
27709 widthIncrement : 0,
27710 heightIncrement : 0,
27714 preserveRatio : false,
27715 transparent: false,
27721 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27723 constrainTo: undefined,
27725 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27727 resizeRegion: undefined,
27731 * Perform a manual resize
27732 * @param {Number} width
27733 * @param {Number} height
27735 resizeTo : function(width, height){
27736 this.el.setSize(width, height);
27737 this.updateChildSize();
27738 this.fireEvent("resize", this, width, height, null);
27742 startSizing : function(e, handle){
27743 this.fireEvent("beforeresize", this, e);
27744 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27747 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27748 this.overlay.unselectable();
27749 this.overlay.enableDisplayMode("block");
27750 this.overlay.on("mousemove", this.onMouseMove, this);
27751 this.overlay.on("mouseup", this.onMouseUp, this);
27753 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27755 this.resizing = true;
27756 this.startBox = this.el.getBox();
27757 this.startPoint = e.getXY();
27758 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27759 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27761 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27762 this.overlay.show();
27764 if(this.constrainTo) {
27765 var ct = Roo.get(this.constrainTo);
27766 this.resizeRegion = ct.getRegion().adjust(
27767 ct.getFrameWidth('t'),
27768 ct.getFrameWidth('l'),
27769 -ct.getFrameWidth('b'),
27770 -ct.getFrameWidth('r')
27774 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27776 this.proxy.setBox(this.startBox);
27778 this.proxy.setStyle('visibility', 'visible');
27784 onMouseDown : function(handle, e){
27787 this.activeHandle = handle;
27788 this.startSizing(e, handle);
27793 onMouseUp : function(e){
27794 var size = this.resizeElement();
27795 this.resizing = false;
27797 this.overlay.hide();
27799 this.fireEvent("resize", this, size.width, size.height, e);
27803 updateChildSize : function(){
27804 if(this.resizeChild){
27806 var child = this.resizeChild;
27807 var adj = this.adjustments;
27808 if(el.dom.offsetWidth){
27809 var b = el.getSize(true);
27810 child.setSize(b.width+adj[0], b.height+adj[1]);
27812 // Second call here for IE
27813 // The first call enables instant resizing and
27814 // the second call corrects scroll bars if they
27817 setTimeout(function(){
27818 if(el.dom.offsetWidth){
27819 var b = el.getSize(true);
27820 child.setSize(b.width+adj[0], b.height+adj[1]);
27828 snap : function(value, inc, min){
27829 if(!inc || !value) return value;
27830 var newValue = value;
27831 var m = value % inc;
27834 newValue = value + (inc-m);
27836 newValue = value - m;
27839 return Math.max(min, newValue);
27843 resizeElement : function(){
27844 var box = this.proxy.getBox();
27845 if(this.updateBox){
27846 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27848 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27850 this.updateChildSize();
27858 constrain : function(v, diff, m, mx){
27861 }else if(v - diff > mx){
27868 onMouseMove : function(e){
27870 try{// try catch so if something goes wrong the user doesn't get hung
27872 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27876 //var curXY = this.startPoint;
27877 var curSize = this.curSize || this.startBox;
27878 var x = this.startBox.x, y = this.startBox.y;
27879 var ox = x, oy = y;
27880 var w = curSize.width, h = curSize.height;
27881 var ow = w, oh = h;
27882 var mw = this.minWidth, mh = this.minHeight;
27883 var mxw = this.maxWidth, mxh = this.maxHeight;
27884 var wi = this.widthIncrement;
27885 var hi = this.heightIncrement;
27887 var eventXY = e.getXY();
27888 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27889 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27891 var pos = this.activeHandle.position;
27896 w = Math.min(Math.max(mw, w), mxw);
27901 h = Math.min(Math.max(mh, h), mxh);
27906 w = Math.min(Math.max(mw, w), mxw);
27907 h = Math.min(Math.max(mh, h), mxh);
27910 diffY = this.constrain(h, diffY, mh, mxh);
27917 var adiffX = Math.abs(diffX);
27918 var sub = (adiffX % wi); // how much
27919 if (sub > (wi/2)) { // far enough to snap
27920 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
27922 // remove difference..
27923 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
27927 x = Math.max(this.minX, x);
27930 diffX = this.constrain(w, diffX, mw, mxw);
27936 w = Math.min(Math.max(mw, w), mxw);
27937 diffY = this.constrain(h, diffY, mh, mxh);
27942 diffX = this.constrain(w, diffX, mw, mxw);
27943 diffY = this.constrain(h, diffY, mh, mxh);
27950 diffX = this.constrain(w, diffX, mw, mxw);
27952 h = Math.min(Math.max(mh, h), mxh);
27958 var sw = this.snap(w, wi, mw);
27959 var sh = this.snap(h, hi, mh);
27960 if(sw != w || sh != h){
27983 if(this.preserveRatio){
27988 h = Math.min(Math.max(mh, h), mxh);
27993 w = Math.min(Math.max(mw, w), mxw);
27998 w = Math.min(Math.max(mw, w), mxw);
28004 w = Math.min(Math.max(mw, w), mxw);
28010 h = Math.min(Math.max(mh, h), mxh);
28018 h = Math.min(Math.max(mh, h), mxh);
28028 h = Math.min(Math.max(mh, h), mxh);
28036 if (pos == 'hdrag') {
28039 this.proxy.setBounds(x, y, w, h);
28041 this.resizeElement();
28048 handleOver : function(){
28050 this.el.addClass("x-resizable-over");
28055 handleOut : function(){
28056 if(!this.resizing){
28057 this.el.removeClass("x-resizable-over");
28062 * Returns the element this component is bound to.
28063 * @return {Roo.Element}
28065 getEl : function(){
28070 * Returns the resizeChild element (or null).
28071 * @return {Roo.Element}
28073 getResizeChild : function(){
28074 return this.resizeChild;
28078 * Destroys this resizable. If the element was wrapped and
28079 * removeEl is not true then the element remains.
28080 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28082 destroy : function(removeEl){
28083 this.proxy.remove();
28085 this.overlay.removeAllListeners();
28086 this.overlay.remove();
28088 var ps = Roo.Resizable.positions;
28090 if(typeof ps[k] != "function" && this[ps[k]]){
28091 var h = this[ps[k]];
28092 h.el.removeAllListeners();
28097 this.el.update("");
28104 // hash to map config positions to true positions
28105 Roo.Resizable.positions = {
28106 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28111 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28113 // only initialize the template if resizable is used
28114 var tpl = Roo.DomHelper.createTemplate(
28115 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28118 Roo.Resizable.Handle.prototype.tpl = tpl;
28120 this.position = pos;
28122 // show north drag fro topdra
28123 var handlepos = pos == 'hdrag' ? 'north' : pos;
28125 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28126 if (pos == 'hdrag') {
28127 this.el.setStyle('cursor', 'pointer');
28129 this.el.unselectable();
28131 this.el.setOpacity(0);
28133 this.el.on("mousedown", this.onMouseDown, this);
28134 if(!disableTrackOver){
28135 this.el.on("mouseover", this.onMouseOver, this);
28136 this.el.on("mouseout", this.onMouseOut, this);
28141 Roo.Resizable.Handle.prototype = {
28142 afterResize : function(rz){
28146 onMouseDown : function(e){
28147 this.rz.onMouseDown(this, e);
28150 onMouseOver : function(e){
28151 this.rz.handleOver(this, e);
28154 onMouseOut : function(e){
28155 this.rz.handleOut(this, e);
28159 * Ext JS Library 1.1.1
28160 * Copyright(c) 2006-2007, Ext JS, LLC.
28162 * Originally Released Under LGPL - original licence link has changed is not relivant.
28165 * <script type="text/javascript">
28169 * @class Roo.Editor
28170 * @extends Roo.Component
28171 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28173 * Create a new Editor
28174 * @param {Roo.form.Field} field The Field object (or descendant)
28175 * @param {Object} config The config object
28177 Roo.Editor = function(field, config){
28178 Roo.Editor.superclass.constructor.call(this, config);
28179 this.field = field;
28182 * @event beforestartedit
28183 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28184 * false from the handler of this event.
28185 * @param {Editor} this
28186 * @param {Roo.Element} boundEl The underlying element bound to this editor
28187 * @param {Mixed} value The field value being set
28189 "beforestartedit" : true,
28192 * Fires when this editor is displayed
28193 * @param {Roo.Element} boundEl The underlying element bound to this editor
28194 * @param {Mixed} value The starting field value
28196 "startedit" : true,
28198 * @event beforecomplete
28199 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28200 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28201 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28202 * event will not fire since no edit actually occurred.
28203 * @param {Editor} this
28204 * @param {Mixed} value The current field value
28205 * @param {Mixed} startValue The original field value
28207 "beforecomplete" : true,
28210 * Fires after editing is complete and any changed value has been written to the underlying field.
28211 * @param {Editor} this
28212 * @param {Mixed} value The current field value
28213 * @param {Mixed} startValue The original field value
28217 * @event specialkey
28218 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28219 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28220 * @param {Roo.form.Field} this
28221 * @param {Roo.EventObject} e The event object
28223 "specialkey" : true
28227 Roo.extend(Roo.Editor, Roo.Component, {
28229 * @cfg {Boolean/String} autosize
28230 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28231 * or "height" to adopt the height only (defaults to false)
28234 * @cfg {Boolean} revertInvalid
28235 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28236 * validation fails (defaults to true)
28239 * @cfg {Boolean} ignoreNoChange
28240 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28241 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28242 * will never be ignored.
28245 * @cfg {Boolean} hideEl
28246 * False to keep the bound element visible while the editor is displayed (defaults to true)
28249 * @cfg {Mixed} value
28250 * The data value of the underlying field (defaults to "")
28254 * @cfg {String} alignment
28255 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28259 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28260 * for bottom-right shadow (defaults to "frame")
28264 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28268 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28270 completeOnEnter : false,
28272 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28274 cancelOnEsc : false,
28276 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28281 onRender : function(ct, position){
28282 this.el = new Roo.Layer({
28283 shadow: this.shadow,
28289 constrain: this.constrain
28291 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28292 if(this.field.msgTarget != 'title'){
28293 this.field.msgTarget = 'qtip';
28295 this.field.render(this.el);
28297 this.field.el.dom.setAttribute('autocomplete', 'off');
28299 this.field.on("specialkey", this.onSpecialKey, this);
28300 if(this.swallowKeys){
28301 this.field.el.swallowEvent(['keydown','keypress']);
28304 this.field.on("blur", this.onBlur, this);
28305 if(this.field.grow){
28306 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28310 onSpecialKey : function(field, e){
28311 //Roo.log('editor onSpecialKey');
28312 if(this.completeOnEnter && e.getKey() == e.ENTER){
28314 this.completeEdit();
28315 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
28318 this.fireEvent('specialkey', field, e);
28323 * Starts the editing process and shows the editor.
28324 * @param {String/HTMLElement/Element} el The element to edit
28325 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28326 * to the innerHTML of el.
28328 startEdit : function(el, value){
28330 this.completeEdit();
28332 this.boundEl = Roo.get(el);
28333 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28334 if(!this.rendered){
28335 this.render(this.parentEl || document.body);
28337 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28340 this.startValue = v;
28341 this.field.setValue(v);
28343 var sz = this.boundEl.getSize();
28344 switch(this.autoSize){
28346 this.setSize(sz.width, "");
28349 this.setSize("", sz.height);
28352 this.setSize(sz.width, sz.height);
28355 this.el.alignTo(this.boundEl, this.alignment);
28356 this.editing = true;
28358 Roo.QuickTips.disable();
28364 * Sets the height and width of this editor.
28365 * @param {Number} width The new width
28366 * @param {Number} height The new height
28368 setSize : function(w, h){
28369 this.field.setSize(w, h);
28376 * Realigns the editor to the bound field based on the current alignment config value.
28378 realign : function(){
28379 this.el.alignTo(this.boundEl, this.alignment);
28383 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28384 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28386 completeEdit : function(remainVisible){
28390 var v = this.getValue();
28391 if(this.revertInvalid !== false && !this.field.isValid()){
28392 v = this.startValue;
28393 this.cancelEdit(true);
28395 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28396 this.editing = false;
28400 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28401 this.editing = false;
28402 if(this.updateEl && this.boundEl){
28403 this.boundEl.update(v);
28405 if(remainVisible !== true){
28408 this.fireEvent("complete", this, v, this.startValue);
28413 onShow : function(){
28415 if(this.hideEl !== false){
28416 this.boundEl.hide();
28419 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28420 this.fixIEFocus = true;
28421 this.deferredFocus.defer(50, this);
28423 this.field.focus();
28425 this.fireEvent("startedit", this.boundEl, this.startValue);
28428 deferredFocus : function(){
28430 this.field.focus();
28435 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28436 * reverted to the original starting value.
28437 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28438 * cancel (defaults to false)
28440 cancelEdit : function(remainVisible){
28442 this.setValue(this.startValue);
28443 if(remainVisible !== true){
28450 onBlur : function(){
28451 if(this.allowBlur !== true && this.editing){
28452 this.completeEdit();
28457 onHide : function(){
28459 this.completeEdit();
28463 if(this.field.collapse){
28464 this.field.collapse();
28467 if(this.hideEl !== false){
28468 this.boundEl.show();
28471 Roo.QuickTips.enable();
28476 * Sets the data value of the editor
28477 * @param {Mixed} value Any valid value supported by the underlying field
28479 setValue : function(v){
28480 this.field.setValue(v);
28484 * Gets the data value of the editor
28485 * @return {Mixed} The data value
28487 getValue : function(){
28488 return this.field.getValue();
28492 * Ext JS Library 1.1.1
28493 * Copyright(c) 2006-2007, Ext JS, LLC.
28495 * Originally Released Under LGPL - original licence link has changed is not relivant.
28498 * <script type="text/javascript">
28502 * @class Roo.BasicDialog
28503 * @extends Roo.util.Observable
28504 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28506 var dlg = new Roo.BasicDialog("my-dlg", {
28515 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28516 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28517 dlg.addButton('Cancel', dlg.hide, dlg);
28520 <b>A Dialog should always be a direct child of the body element.</b>
28521 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28522 * @cfg {String} title Default text to display in the title bar (defaults to null)
28523 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28524 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28525 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28526 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28527 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28528 * (defaults to null with no animation)
28529 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28530 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28531 * property for valid values (defaults to 'all')
28532 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28533 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28534 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28535 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28536 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28537 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28538 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28539 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28540 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28541 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28542 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28543 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28544 * draggable = true (defaults to false)
28545 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28546 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28547 * shadow (defaults to false)
28548 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28549 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28550 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28551 * @cfg {Array} buttons Array of buttons
28552 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28554 * Create a new BasicDialog.
28555 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28556 * @param {Object} config Configuration options
28558 Roo.BasicDialog = function(el, config){
28559 this.el = Roo.get(el);
28560 var dh = Roo.DomHelper;
28561 if(!this.el && config && config.autoCreate){
28562 if(typeof config.autoCreate == "object"){
28563 if(!config.autoCreate.id){
28564 config.autoCreate.id = el;
28566 this.el = dh.append(document.body,
28567 config.autoCreate, true);
28569 this.el = dh.append(document.body,
28570 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28574 el.setDisplayed(true);
28575 el.hide = this.hideAction;
28577 el.addClass("x-dlg");
28579 Roo.apply(this, config);
28581 this.proxy = el.createProxy("x-dlg-proxy");
28582 this.proxy.hide = this.hideAction;
28583 this.proxy.setOpacity(.5);
28587 el.setWidth(config.width);
28590 el.setHeight(config.height);
28592 this.size = el.getSize();
28593 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28594 this.xy = [config.x,config.y];
28596 this.xy = el.getCenterXY(true);
28598 /** The header element @type Roo.Element */
28599 this.header = el.child("> .x-dlg-hd");
28600 /** The body element @type Roo.Element */
28601 this.body = el.child("> .x-dlg-bd");
28602 /** The footer element @type Roo.Element */
28603 this.footer = el.child("> .x-dlg-ft");
28606 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28609 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28612 this.header.unselectable();
28614 this.header.update(this.title);
28616 // this element allows the dialog to be focused for keyboard event
28617 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28618 this.focusEl.swallowEvent("click", true);
28620 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28622 // wrap the body and footer for special rendering
28623 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28625 this.bwrap.dom.appendChild(this.footer.dom);
28628 this.bg = this.el.createChild({
28629 tag: "div", cls:"x-dlg-bg",
28630 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28632 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28635 if(this.autoScroll !== false && !this.autoTabs){
28636 this.body.setStyle("overflow", "auto");
28639 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28641 if(this.closable !== false){
28642 this.el.addClass("x-dlg-closable");
28643 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28644 this.close.on("click", this.closeClick, this);
28645 this.close.addClassOnOver("x-dlg-close-over");
28647 if(this.collapsible !== false){
28648 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28649 this.collapseBtn.on("click", this.collapseClick, this);
28650 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28651 this.header.on("dblclick", this.collapseClick, this);
28653 if(this.resizable !== false){
28654 this.el.addClass("x-dlg-resizable");
28655 this.resizer = new Roo.Resizable(el, {
28656 minWidth: this.minWidth || 80,
28657 minHeight:this.minHeight || 80,
28658 handles: this.resizeHandles || "all",
28661 this.resizer.on("beforeresize", this.beforeResize, this);
28662 this.resizer.on("resize", this.onResize, this);
28664 if(this.draggable !== false){
28665 el.addClass("x-dlg-draggable");
28666 if (!this.proxyDrag) {
28667 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28670 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28672 dd.setHandleElId(this.header.id);
28673 dd.endDrag = this.endMove.createDelegate(this);
28674 dd.startDrag = this.startMove.createDelegate(this);
28675 dd.onDrag = this.onDrag.createDelegate(this);
28680 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28681 this.mask.enableDisplayMode("block");
28683 this.el.addClass("x-dlg-modal");
28686 this.shadow = new Roo.Shadow({
28687 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28688 offset : this.shadowOffset
28691 this.shadowOffset = 0;
28693 if(Roo.useShims && this.shim !== false){
28694 this.shim = this.el.createShim();
28695 this.shim.hide = this.hideAction;
28703 if (this.buttons) {
28704 var bts= this.buttons;
28706 Roo.each(bts, function(b) {
28715 * Fires when a key is pressed
28716 * @param {Roo.BasicDialog} this
28717 * @param {Roo.EventObject} e
28722 * Fires when this dialog is moved by the user.
28723 * @param {Roo.BasicDialog} this
28724 * @param {Number} x The new page X
28725 * @param {Number} y The new page Y
28730 * Fires when this dialog is resized by the user.
28731 * @param {Roo.BasicDialog} this
28732 * @param {Number} width The new width
28733 * @param {Number} height The new height
28737 * @event beforehide
28738 * Fires before this dialog is hidden.
28739 * @param {Roo.BasicDialog} this
28741 "beforehide" : true,
28744 * Fires when this dialog is hidden.
28745 * @param {Roo.BasicDialog} this
28749 * @event beforeshow
28750 * Fires before this dialog is shown.
28751 * @param {Roo.BasicDialog} this
28753 "beforeshow" : true,
28756 * Fires when this dialog is shown.
28757 * @param {Roo.BasicDialog} this
28761 el.on("keydown", this.onKeyDown, this);
28762 el.on("mousedown", this.toFront, this);
28763 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28765 Roo.DialogManager.register(this);
28766 Roo.BasicDialog.superclass.constructor.call(this);
28769 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28770 shadowOffset: Roo.isIE ? 6 : 5,
28773 minButtonWidth: 75,
28774 defaultButton: null,
28775 buttonAlign: "right",
28780 * Sets the dialog title text
28781 * @param {String} text The title text to display
28782 * @return {Roo.BasicDialog} this
28784 setTitle : function(text){
28785 this.header.update(text);
28790 closeClick : function(){
28795 collapseClick : function(){
28796 this[this.collapsed ? "expand" : "collapse"]();
28800 * Collapses the dialog to its minimized state (only the title bar is visible).
28801 * Equivalent to the user clicking the collapse dialog button.
28803 collapse : function(){
28804 if(!this.collapsed){
28805 this.collapsed = true;
28806 this.el.addClass("x-dlg-collapsed");
28807 this.restoreHeight = this.el.getHeight();
28808 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28813 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28814 * clicking the expand dialog button.
28816 expand : function(){
28817 if(this.collapsed){
28818 this.collapsed = false;
28819 this.el.removeClass("x-dlg-collapsed");
28820 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28825 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28826 * @return {Roo.TabPanel} The tabs component
28828 initTabs : function(){
28829 var tabs = this.getTabs();
28830 while(tabs.getTab(0)){
28833 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28835 tabs.addTab(Roo.id(dom), dom.title);
28843 beforeResize : function(){
28844 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28848 onResize : function(){
28849 this.refreshSize();
28850 this.syncBodyHeight();
28851 this.adjustAssets();
28853 this.fireEvent("resize", this, this.size.width, this.size.height);
28857 onKeyDown : function(e){
28858 if(this.isVisible()){
28859 this.fireEvent("keydown", this, e);
28864 * Resizes the dialog.
28865 * @param {Number} width
28866 * @param {Number} height
28867 * @return {Roo.BasicDialog} this
28869 resizeTo : function(width, height){
28870 this.el.setSize(width, height);
28871 this.size = {width: width, height: height};
28872 this.syncBodyHeight();
28873 if(this.fixedcenter){
28876 if(this.isVisible()){
28877 this.constrainXY();
28878 this.adjustAssets();
28880 this.fireEvent("resize", this, width, height);
28886 * Resizes the dialog to fit the specified content size.
28887 * @param {Number} width
28888 * @param {Number} height
28889 * @return {Roo.BasicDialog} this
28891 setContentSize : function(w, h){
28892 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28893 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28894 //if(!this.el.isBorderBox()){
28895 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28896 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28899 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28900 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28902 this.resizeTo(w, h);
28907 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28908 * executed in response to a particular key being pressed while the dialog is active.
28909 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28910 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28911 * @param {Function} fn The function to call
28912 * @param {Object} scope (optional) The scope of the function
28913 * @return {Roo.BasicDialog} this
28915 addKeyListener : function(key, fn, scope){
28916 var keyCode, shift, ctrl, alt;
28917 if(typeof key == "object" && !(key instanceof Array)){
28918 keyCode = key["key"];
28919 shift = key["shift"];
28920 ctrl = key["ctrl"];
28925 var handler = function(dlg, e){
28926 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28927 var k = e.getKey();
28928 if(keyCode instanceof Array){
28929 for(var i = 0, len = keyCode.length; i < len; i++){
28930 if(keyCode[i] == k){
28931 fn.call(scope || window, dlg, k, e);
28937 fn.call(scope || window, dlg, k, e);
28942 this.on("keydown", handler);
28947 * Returns the TabPanel component (creates it if it doesn't exist).
28948 * Note: If you wish to simply check for the existence of tabs without creating them,
28949 * check for a null 'tabs' property.
28950 * @return {Roo.TabPanel} The tabs component
28952 getTabs : function(){
28954 this.el.addClass("x-dlg-auto-tabs");
28955 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28956 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28962 * Adds a button to the footer section of the dialog.
28963 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28964 * object or a valid Roo.DomHelper element config
28965 * @param {Function} handler The function called when the button is clicked
28966 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28967 * @return {Roo.Button} The new button
28969 addButton : function(config, handler, scope){
28970 var dh = Roo.DomHelper;
28972 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28974 if(!this.btnContainer){
28975 var tb = this.footer.createChild({
28977 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28978 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28980 this.btnContainer = tb.firstChild.firstChild.firstChild;
28985 minWidth: this.minButtonWidth,
28988 if(typeof config == "string"){
28989 bconfig.text = config;
28992 bconfig.dhconfig = config;
28994 Roo.apply(bconfig, config);
28998 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28999 bconfig.position = Math.max(0, bconfig.position);
29000 fc = this.btnContainer.childNodes[bconfig.position];
29003 var btn = new Roo.Button(
29005 this.btnContainer.insertBefore(document.createElement("td"),fc)
29006 : this.btnContainer.appendChild(document.createElement("td")),
29007 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29010 this.syncBodyHeight();
29013 * Array of all the buttons that have been added to this dialog via addButton
29018 this.buttons.push(btn);
29023 * Sets the default button to be focused when the dialog is displayed.
29024 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29025 * @return {Roo.BasicDialog} this
29027 setDefaultButton : function(btn){
29028 this.defaultButton = btn;
29033 getHeaderFooterHeight : function(safe){
29036 height += this.header.getHeight();
29039 var fm = this.footer.getMargins();
29040 height += (this.footer.getHeight()+fm.top+fm.bottom);
29042 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29043 height += this.centerBg.getPadding("tb");
29048 syncBodyHeight : function(){
29049 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29050 var height = this.size.height - this.getHeaderFooterHeight(false);
29051 bd.setHeight(height-bd.getMargins("tb"));
29052 var hh = this.header.getHeight();
29053 var h = this.size.height-hh;
29055 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29056 bw.setHeight(h-cb.getPadding("tb"));
29057 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29058 bd.setWidth(bw.getWidth(true));
29060 this.tabs.syncHeight();
29062 this.tabs.el.repaint();
29068 * Restores the previous state of the dialog if Roo.state is configured.
29069 * @return {Roo.BasicDialog} this
29071 restoreState : function(){
29072 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29073 if(box && box.width){
29074 this.xy = [box.x, box.y];
29075 this.resizeTo(box.width, box.height);
29081 beforeShow : function(){
29083 if(this.fixedcenter){
29084 this.xy = this.el.getCenterXY(true);
29087 Roo.get(document.body).addClass("x-body-masked");
29088 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29091 this.constrainXY();
29095 animShow : function(){
29096 var b = Roo.get(this.animateTarget).getBox();
29097 this.proxy.setSize(b.width, b.height);
29098 this.proxy.setLocation(b.x, b.y);
29100 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29101 true, .35, this.showEl.createDelegate(this));
29105 * Shows the dialog.
29106 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29107 * @return {Roo.BasicDialog} this
29109 show : function(animateTarget){
29110 if (this.fireEvent("beforeshow", this) === false){
29113 if(this.syncHeightBeforeShow){
29114 this.syncBodyHeight();
29115 }else if(this.firstShow){
29116 this.firstShow = false;
29117 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29119 this.animateTarget = animateTarget || this.animateTarget;
29120 if(!this.el.isVisible()){
29122 if(this.animateTarget && Roo.get(this.animateTarget)){
29132 showEl : function(){
29134 this.el.setXY(this.xy);
29136 this.adjustAssets(true);
29139 // IE peekaboo bug - fix found by Dave Fenwick
29143 this.fireEvent("show", this);
29147 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29148 * dialog itself will receive focus.
29150 focus : function(){
29151 if(this.defaultButton){
29152 this.defaultButton.focus();
29154 this.focusEl.focus();
29159 constrainXY : function(){
29160 if(this.constraintoviewport !== false){
29161 if(!this.viewSize){
29162 if(this.container){
29163 var s = this.container.getSize();
29164 this.viewSize = [s.width, s.height];
29166 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29169 var s = Roo.get(this.container||document).getScroll();
29171 var x = this.xy[0], y = this.xy[1];
29172 var w = this.size.width, h = this.size.height;
29173 var vw = this.viewSize[0], vh = this.viewSize[1];
29174 // only move it if it needs it
29176 // first validate right/bottom
29177 if(x + w > vw+s.left){
29181 if(y + h > vh+s.top){
29185 // then make sure top/left isn't negative
29197 if(this.isVisible()){
29198 this.el.setLocation(x, y);
29199 this.adjustAssets();
29206 onDrag : function(){
29207 if(!this.proxyDrag){
29208 this.xy = this.el.getXY();
29209 this.adjustAssets();
29214 adjustAssets : function(doShow){
29215 var x = this.xy[0], y = this.xy[1];
29216 var w = this.size.width, h = this.size.height;
29217 if(doShow === true){
29219 this.shadow.show(this.el);
29225 if(this.shadow && this.shadow.isVisible()){
29226 this.shadow.show(this.el);
29228 if(this.shim && this.shim.isVisible()){
29229 this.shim.setBounds(x, y, w, h);
29234 adjustViewport : function(w, h){
29236 w = Roo.lib.Dom.getViewWidth();
29237 h = Roo.lib.Dom.getViewHeight();
29240 this.viewSize = [w, h];
29241 if(this.modal && this.mask.isVisible()){
29242 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29243 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29245 if(this.isVisible()){
29246 this.constrainXY();
29251 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29252 * shadow, proxy, mask, etc.) Also removes all event listeners.
29253 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29255 destroy : function(removeEl){
29256 if(this.isVisible()){
29257 this.animateTarget = null;
29260 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29262 this.tabs.destroy(removeEl);
29275 for(var i = 0, len = this.buttons.length; i < len; i++){
29276 this.buttons[i].destroy();
29279 this.el.removeAllListeners();
29280 if(removeEl === true){
29281 this.el.update("");
29284 Roo.DialogManager.unregister(this);
29288 startMove : function(){
29289 if(this.proxyDrag){
29292 if(this.constraintoviewport !== false){
29293 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29298 endMove : function(){
29299 if(!this.proxyDrag){
29300 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29302 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29305 this.refreshSize();
29306 this.adjustAssets();
29308 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29312 * Brings this dialog to the front of any other visible dialogs
29313 * @return {Roo.BasicDialog} this
29315 toFront : function(){
29316 Roo.DialogManager.bringToFront(this);
29321 * Sends this dialog to the back (under) of any other visible dialogs
29322 * @return {Roo.BasicDialog} this
29324 toBack : function(){
29325 Roo.DialogManager.sendToBack(this);
29330 * Centers this dialog in the viewport
29331 * @return {Roo.BasicDialog} this
29333 center : function(){
29334 var xy = this.el.getCenterXY(true);
29335 this.moveTo(xy[0], xy[1]);
29340 * Moves the dialog's top-left corner to the specified point
29341 * @param {Number} x
29342 * @param {Number} y
29343 * @return {Roo.BasicDialog} this
29345 moveTo : function(x, y){
29347 if(this.isVisible()){
29348 this.el.setXY(this.xy);
29349 this.adjustAssets();
29355 * Aligns the dialog to the specified element
29356 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29357 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29358 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29359 * @return {Roo.BasicDialog} this
29361 alignTo : function(element, position, offsets){
29362 this.xy = this.el.getAlignToXY(element, position, offsets);
29363 if(this.isVisible()){
29364 this.el.setXY(this.xy);
29365 this.adjustAssets();
29371 * Anchors an element to another element and realigns it when the window is resized.
29372 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29373 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29374 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29375 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29376 * is a number, it is used as the buffer delay (defaults to 50ms).
29377 * @return {Roo.BasicDialog} this
29379 anchorTo : function(el, alignment, offsets, monitorScroll){
29380 var action = function(){
29381 this.alignTo(el, alignment, offsets);
29383 Roo.EventManager.onWindowResize(action, this);
29384 var tm = typeof monitorScroll;
29385 if(tm != 'undefined'){
29386 Roo.EventManager.on(window, 'scroll', action, this,
29387 {buffer: tm == 'number' ? monitorScroll : 50});
29394 * Returns true if the dialog is visible
29395 * @return {Boolean}
29397 isVisible : function(){
29398 return this.el.isVisible();
29402 animHide : function(callback){
29403 var b = Roo.get(this.animateTarget).getBox();
29405 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29407 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29408 this.hideEl.createDelegate(this, [callback]));
29412 * Hides the dialog.
29413 * @param {Function} callback (optional) Function to call when the dialog is hidden
29414 * @return {Roo.BasicDialog} this
29416 hide : function(callback){
29417 if (this.fireEvent("beforehide", this) === false){
29421 this.shadow.hide();
29426 // sometimes animateTarget seems to get set.. causing problems...
29427 // this just double checks..
29428 if(this.animateTarget && Roo.get(this.animateTarget)) {
29429 this.animHide(callback);
29432 this.hideEl(callback);
29438 hideEl : function(callback){
29442 Roo.get(document.body).removeClass("x-body-masked");
29444 this.fireEvent("hide", this);
29445 if(typeof callback == "function"){
29451 hideAction : function(){
29452 this.setLeft("-10000px");
29453 this.setTop("-10000px");
29454 this.setStyle("visibility", "hidden");
29458 refreshSize : function(){
29459 this.size = this.el.getSize();
29460 this.xy = this.el.getXY();
29461 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29465 // z-index is managed by the DialogManager and may be overwritten at any time
29466 setZIndex : function(index){
29468 this.mask.setStyle("z-index", index);
29471 this.shim.setStyle("z-index", ++index);
29474 this.shadow.setZIndex(++index);
29476 this.el.setStyle("z-index", ++index);
29478 this.proxy.setStyle("z-index", ++index);
29481 this.resizer.proxy.setStyle("z-index", ++index);
29484 this.lastZIndex = index;
29488 * Returns the element for this dialog
29489 * @return {Roo.Element} The underlying dialog Element
29491 getEl : function(){
29497 * @class Roo.DialogManager
29498 * Provides global access to BasicDialogs that have been created and
29499 * support for z-indexing (layering) multiple open dialogs.
29501 Roo.DialogManager = function(){
29503 var accessList = [];
29507 var sortDialogs = function(d1, d2){
29508 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29512 var orderDialogs = function(){
29513 accessList.sort(sortDialogs);
29514 var seed = Roo.DialogManager.zseed;
29515 for(var i = 0, len = accessList.length; i < len; i++){
29516 var dlg = accessList[i];
29518 dlg.setZIndex(seed + (i*10));
29525 * The starting z-index for BasicDialogs (defaults to 9000)
29526 * @type Number The z-index value
29531 register : function(dlg){
29532 list[dlg.id] = dlg;
29533 accessList.push(dlg);
29537 unregister : function(dlg){
29538 delete list[dlg.id];
29541 if(!accessList.indexOf){
29542 for( i = 0, len = accessList.length; i < len; i++){
29543 if(accessList[i] == dlg){
29544 accessList.splice(i, 1);
29549 i = accessList.indexOf(dlg);
29551 accessList.splice(i, 1);
29557 * Gets a registered dialog by id
29558 * @param {String/Object} id The id of the dialog or a dialog
29559 * @return {Roo.BasicDialog} this
29561 get : function(id){
29562 return typeof id == "object" ? id : list[id];
29566 * Brings the specified dialog to the front
29567 * @param {String/Object} dlg The id of the dialog or a dialog
29568 * @return {Roo.BasicDialog} this
29570 bringToFront : function(dlg){
29571 dlg = this.get(dlg);
29574 dlg._lastAccess = new Date().getTime();
29581 * Sends the specified dialog to the back
29582 * @param {String/Object} dlg The id of the dialog or a dialog
29583 * @return {Roo.BasicDialog} this
29585 sendToBack : function(dlg){
29586 dlg = this.get(dlg);
29587 dlg._lastAccess = -(new Date().getTime());
29593 * Hides all dialogs
29595 hideAll : function(){
29596 for(var id in list){
29597 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29606 * @class Roo.LayoutDialog
29607 * @extends Roo.BasicDialog
29608 * Dialog which provides adjustments for working with a layout in a Dialog.
29609 * Add your necessary layout config options to the dialog's config.<br>
29610 * Example usage (including a nested layout):
29613 dialog = new Roo.LayoutDialog("download-dlg", {
29622 // layout config merges with the dialog config
29624 tabPosition: "top",
29625 alwaysShowTabs: true
29628 dialog.addKeyListener(27, dialog.hide, dialog);
29629 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29630 dialog.addButton("Build It!", this.getDownload, this);
29632 // we can even add nested layouts
29633 var innerLayout = new Roo.BorderLayout("dl-inner", {
29643 innerLayout.beginUpdate();
29644 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29645 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29646 innerLayout.endUpdate(true);
29648 var layout = dialog.getLayout();
29649 layout.beginUpdate();
29650 layout.add("center", new Roo.ContentPanel("standard-panel",
29651 {title: "Download the Source", fitToFrame:true}));
29652 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29653 {title: "Build your own roo.js"}));
29654 layout.getRegion("center").showPanel(sp);
29655 layout.endUpdate();
29659 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29660 * @param {Object} config configuration options
29662 Roo.LayoutDialog = function(el, cfg){
29665 if (typeof(cfg) == 'undefined') {
29666 config = Roo.apply({}, el);
29667 // not sure why we use documentElement here.. - it should always be body.
29668 // IE7 borks horribly if we use documentElement.
29669 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
29670 //config.autoCreate = true;
29674 config.autoTabs = false;
29675 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29676 this.body.setStyle({overflow:"hidden", position:"relative"});
29677 this.layout = new Roo.BorderLayout(this.body.dom, config);
29678 this.layout.monitorWindowResize = false;
29679 this.el.addClass("x-dlg-auto-layout");
29680 // fix case when center region overwrites center function
29681 this.center = Roo.BasicDialog.prototype.center;
29682 this.on("show", this.layout.layout, this.layout, true);
29683 if (config.items) {
29684 var xitems = config.items;
29685 delete config.items;
29686 Roo.each(xitems, this.addxtype, this);
29691 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29693 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29696 endUpdate : function(){
29697 this.layout.endUpdate();
29701 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29704 beginUpdate : function(){
29705 this.layout.beginUpdate();
29709 * Get the BorderLayout for this dialog
29710 * @return {Roo.BorderLayout}
29712 getLayout : function(){
29713 return this.layout;
29716 showEl : function(){
29717 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29719 this.layout.layout();
29724 // Use the syncHeightBeforeShow config option to control this automatically
29725 syncBodyHeight : function(){
29726 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29727 if(this.layout){this.layout.layout();}
29731 * Add an xtype element (actually adds to the layout.)
29732 * @return {Object} xdata xtype object data.
29735 addxtype : function(c) {
29736 return this.layout.addxtype(c);
29740 * Ext JS Library 1.1.1
29741 * Copyright(c) 2006-2007, Ext JS, LLC.
29743 * Originally Released Under LGPL - original licence link has changed is not relivant.
29746 * <script type="text/javascript">
29750 * @class Roo.MessageBox
29751 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29755 Roo.Msg.alert('Status', 'Changes saved successfully.');
29757 // Prompt for user data:
29758 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29760 // process text value...
29764 // Show a dialog using config options:
29766 title:'Save Changes?',
29767 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29768 buttons: Roo.Msg.YESNOCANCEL,
29775 Roo.MessageBox = function(){
29776 var dlg, opt, mask, waitTimer;
29777 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29778 var buttons, activeTextEl, bwidth;
29781 var handleButton = function(button){
29783 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29787 var handleHide = function(){
29788 if(opt && opt.cls){
29789 dlg.el.removeClass(opt.cls);
29792 Roo.TaskMgr.stop(waitTimer);
29798 var updateButtons = function(b){
29801 buttons["ok"].hide();
29802 buttons["cancel"].hide();
29803 buttons["yes"].hide();
29804 buttons["no"].hide();
29805 dlg.footer.dom.style.display = 'none';
29808 dlg.footer.dom.style.display = '';
29809 for(var k in buttons){
29810 if(typeof buttons[k] != "function"){
29813 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29814 width += buttons[k].el.getWidth()+15;
29824 var handleEsc = function(d, k, e){
29825 if(opt && opt.closable !== false){
29835 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29836 * @return {Roo.BasicDialog} The BasicDialog element
29838 getDialog : function(){
29840 dlg = new Roo.BasicDialog("x-msg-box", {
29845 constraintoviewport:false,
29847 collapsible : false,
29850 width:400, height:100,
29851 buttonAlign:"center",
29852 closeClick : function(){
29853 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29854 handleButton("no");
29856 handleButton("cancel");
29860 dlg.on("hide", handleHide);
29862 dlg.addKeyListener(27, handleEsc);
29864 var bt = this.buttonText;
29865 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29866 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29867 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29868 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29869 bodyEl = dlg.body.createChild({
29871 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>'
29873 msgEl = bodyEl.dom.firstChild;
29874 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29875 textboxEl.enableDisplayMode();
29876 textboxEl.addKeyListener([10,13], function(){
29877 if(dlg.isVisible() && opt && opt.buttons){
29878 if(opt.buttons.ok){
29879 handleButton("ok");
29880 }else if(opt.buttons.yes){
29881 handleButton("yes");
29885 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29886 textareaEl.enableDisplayMode();
29887 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29888 progressEl.enableDisplayMode();
29889 var pf = progressEl.dom.firstChild;
29891 pp = Roo.get(pf.firstChild);
29892 pp.setHeight(pf.offsetHeight);
29900 * Updates the message box body text
29901 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29902 * the XHTML-compliant non-breaking space character '&#160;')
29903 * @return {Roo.MessageBox} This message box
29905 updateText : function(text){
29906 if(!dlg.isVisible() && !opt.width){
29907 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29909 msgEl.innerHTML = text || ' ';
29910 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29911 Math.max(opt.minWidth || this.minWidth, bwidth));
29913 activeTextEl.setWidth(w);
29915 if(dlg.isVisible()){
29916 dlg.fixedcenter = false;
29918 dlg.setContentSize(w, bodyEl.getHeight());
29919 if(dlg.isVisible()){
29920 dlg.fixedcenter = true;
29926 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29927 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29928 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29929 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29930 * @return {Roo.MessageBox} This message box
29932 updateProgress : function(value, text){
29934 this.updateText(text);
29936 if (pp) { // weird bug on my firefox - for some reason this is not defined
29937 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29943 * Returns true if the message box is currently displayed
29944 * @return {Boolean} True if the message box is visible, else false
29946 isVisible : function(){
29947 return dlg && dlg.isVisible();
29951 * Hides the message box if it is displayed
29954 if(this.isVisible()){
29960 * Displays a new message box, or reinitializes an existing message box, based on the config options
29961 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29962 * The following config object properties are supported:
29964 Property Type Description
29965 ---------- --------------- ------------------------------------------------------------------------------------
29966 animEl String/Element An id or Element from which the message box should animate as it opens and
29967 closes (defaults to undefined)
29968 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29969 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29970 closable Boolean False to hide the top-right close button (defaults to true). Note that
29971 progress and wait dialogs will ignore this property and always hide the
29972 close button as they can only be closed programmatically.
29973 cls String A custom CSS class to apply to the message box element
29974 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29975 displayed (defaults to 75)
29976 fn Function A callback function to execute after closing the dialog. The arguments to the
29977 function will be btn (the name of the button that was clicked, if applicable,
29978 e.g. "ok"), and text (the value of the active text field, if applicable).
29979 Progress and wait dialogs will ignore this option since they do not respond to
29980 user actions and can only be closed programmatically, so any required function
29981 should be called by the same code after it closes the dialog.
29982 icon String A CSS class that provides a background image to be used as an icon for
29983 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29984 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29985 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29986 modal Boolean False to allow user interaction with the page while the message box is
29987 displayed (defaults to true)
29988 msg String A string that will replace the existing message box body text (defaults
29989 to the XHTML-compliant non-breaking space character ' ')
29990 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29991 progress Boolean True to display a progress bar (defaults to false)
29992 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29993 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29994 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29995 title String The title text
29996 value String The string value to set into the active textbox element if displayed
29997 wait Boolean True to display a progress bar (defaults to false)
29998 width Number The width of the dialog in pixels
30005 msg: 'Please enter your address:',
30007 buttons: Roo.MessageBox.OKCANCEL,
30010 animEl: 'addAddressBtn'
30013 * @param {Object} config Configuration options
30014 * @return {Roo.MessageBox} This message box
30016 show : function(options){
30017 if(this.isVisible()){
30020 var d = this.getDialog();
30022 d.setTitle(opt.title || " ");
30023 d.close.setDisplayed(opt.closable !== false);
30024 activeTextEl = textboxEl;
30025 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30030 textareaEl.setHeight(typeof opt.multiline == "number" ?
30031 opt.multiline : this.defaultTextHeight);
30032 activeTextEl = textareaEl;
30041 progressEl.setDisplayed(opt.progress === true);
30042 this.updateProgress(0);
30043 activeTextEl.dom.value = opt.value || "";
30045 dlg.setDefaultButton(activeTextEl);
30047 var bs = opt.buttons;
30050 db = buttons["ok"];
30051 }else if(bs && bs.yes){
30052 db = buttons["yes"];
30054 dlg.setDefaultButton(db);
30056 bwidth = updateButtons(opt.buttons);
30057 this.updateText(opt.msg);
30059 d.el.addClass(opt.cls);
30061 d.proxyDrag = opt.proxyDrag === true;
30062 d.modal = opt.modal !== false;
30063 d.mask = opt.modal !== false ? mask : false;
30064 if(!d.isVisible()){
30065 // force it to the end of the z-index stack so it gets a cursor in FF
30066 document.body.appendChild(dlg.el.dom);
30067 d.animateTarget = null;
30068 d.show(options.animEl);
30074 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30075 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30076 * and closing the message box when the process is complete.
30077 * @param {String} title The title bar text
30078 * @param {String} msg The message box body text
30079 * @return {Roo.MessageBox} This message box
30081 progress : function(title, msg){
30088 minWidth: this.minProgressWidth,
30095 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30096 * If a callback function is passed it will be called after the user clicks the button, and the
30097 * id of the button that was clicked will be passed as the only parameter to the callback
30098 * (could also be the top-right close button).
30099 * @param {String} title The title bar text
30100 * @param {String} msg The message box body text
30101 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30102 * @param {Object} scope (optional) The scope of the callback function
30103 * @return {Roo.MessageBox} This message box
30105 alert : function(title, msg, fn, scope){
30118 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30119 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30120 * You are responsible for closing the message box when the process is complete.
30121 * @param {String} msg The message box body text
30122 * @param {String} title (optional) The title bar text
30123 * @return {Roo.MessageBox} This message box
30125 wait : function(msg, title){
30136 waitTimer = Roo.TaskMgr.start({
30138 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30146 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30147 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30148 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30149 * @param {String} title The title bar text
30150 * @param {String} msg The message box body text
30151 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30152 * @param {Object} scope (optional) The scope of the callback function
30153 * @return {Roo.MessageBox} This message box
30155 confirm : function(title, msg, fn, scope){
30159 buttons: this.YESNO,
30168 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30169 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30170 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30171 * (could also be the top-right close button) and the text that was entered will be passed as the two
30172 * parameters to the callback.
30173 * @param {String} title The title bar text
30174 * @param {String} msg The message box body text
30175 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30176 * @param {Object} scope (optional) The scope of the callback function
30177 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30178 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30179 * @return {Roo.MessageBox} This message box
30181 prompt : function(title, msg, fn, scope, multiline){
30185 buttons: this.OKCANCEL,
30190 multiline: multiline,
30197 * Button config that displays a single OK button
30202 * Button config that displays Yes and No buttons
30205 YESNO : {yes:true, no:true},
30207 * Button config that displays OK and Cancel buttons
30210 OKCANCEL : {ok:true, cancel:true},
30212 * Button config that displays Yes, No and Cancel buttons
30215 YESNOCANCEL : {yes:true, no:true, cancel:true},
30218 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30221 defaultTextHeight : 75,
30223 * The maximum width in pixels of the message box (defaults to 600)
30228 * The minimum width in pixels of the message box (defaults to 100)
30233 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30234 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30237 minProgressWidth : 250,
30239 * An object containing the default button text strings that can be overriden for localized language support.
30240 * Supported properties are: ok, cancel, yes and no.
30241 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30254 * Shorthand for {@link Roo.MessageBox}
30256 Roo.Msg = Roo.MessageBox;/*
30258 * Ext JS Library 1.1.1
30259 * Copyright(c) 2006-2007, Ext JS, LLC.
30261 * Originally Released Under LGPL - original licence link has changed is not relivant.
30264 * <script type="text/javascript">
30267 * @class Roo.QuickTips
30268 * Provides attractive and customizable tooltips for any element.
30271 Roo.QuickTips = function(){
30272 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30273 var ce, bd, xy, dd;
30274 var visible = false, disabled = true, inited = false;
30275 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30277 var onOver = function(e){
30281 var t = e.getTarget();
30282 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30285 if(ce && t == ce.el){
30286 clearTimeout(hideProc);
30289 if(t && tagEls[t.id]){
30290 tagEls[t.id].el = t;
30291 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30294 var ttp, et = Roo.fly(t);
30295 var ns = cfg.namespace;
30296 if(tm.interceptTitles && t.title){
30299 t.removeAttribute("title");
30300 e.preventDefault();
30302 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30305 showProc = show.defer(tm.showDelay, tm, [{
30308 width: et.getAttributeNS(ns, cfg.width),
30309 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30310 title: et.getAttributeNS(ns, cfg.title),
30311 cls: et.getAttributeNS(ns, cfg.cls)
30316 var onOut = function(e){
30317 clearTimeout(showProc);
30318 var t = e.getTarget();
30319 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30320 hideProc = setTimeout(hide, tm.hideDelay);
30324 var onMove = function(e){
30330 if(tm.trackMouse && ce){
30335 var onDown = function(e){
30336 clearTimeout(showProc);
30337 clearTimeout(hideProc);
30339 if(tm.hideOnClick){
30342 tm.enable.defer(100, tm);
30347 var getPad = function(){
30348 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30351 var show = function(o){
30355 clearTimeout(dismissProc);
30357 if(removeCls){ // in case manually hidden
30358 el.removeClass(removeCls);
30362 el.addClass(ce.cls);
30363 removeCls = ce.cls;
30366 tipTitle.update(ce.title);
30369 tipTitle.update('');
30372 el.dom.style.width = tm.maxWidth+'px';
30373 //tipBody.dom.style.width = '';
30374 tipBodyText.update(o.text);
30375 var p = getPad(), w = ce.width;
30377 var td = tipBodyText.dom;
30378 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30379 if(aw > tm.maxWidth){
30381 }else if(aw < tm.minWidth){
30387 //tipBody.setWidth(w);
30388 el.setWidth(parseInt(w, 10) + p);
30389 if(ce.autoHide === false){
30390 close.setDisplayed(true);
30395 close.setDisplayed(false);
30401 el.avoidY = xy[1]-18;
30406 el.setStyle("visibility", "visible");
30407 el.fadeIn({callback: afterShow});
30413 var afterShow = function(){
30417 if(tm.autoDismiss && ce.autoHide !== false){
30418 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30423 var hide = function(noanim){
30424 clearTimeout(dismissProc);
30425 clearTimeout(hideProc);
30427 if(el.isVisible()){
30429 if(noanim !== true && tm.animate){
30430 el.fadeOut({callback: afterHide});
30437 var afterHide = function(){
30440 el.removeClass(removeCls);
30447 * @cfg {Number} minWidth
30448 * The minimum width of the quick tip (defaults to 40)
30452 * @cfg {Number} maxWidth
30453 * The maximum width of the quick tip (defaults to 300)
30457 * @cfg {Boolean} interceptTitles
30458 * True to automatically use the element's DOM title value if available (defaults to false)
30460 interceptTitles : false,
30462 * @cfg {Boolean} trackMouse
30463 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30465 trackMouse : false,
30467 * @cfg {Boolean} hideOnClick
30468 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30470 hideOnClick : true,
30472 * @cfg {Number} showDelay
30473 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30477 * @cfg {Number} hideDelay
30478 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30482 * @cfg {Boolean} autoHide
30483 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30484 * Used in conjunction with hideDelay.
30489 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30490 * (defaults to true). Used in conjunction with autoDismissDelay.
30492 autoDismiss : true,
30495 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30497 autoDismissDelay : 5000,
30499 * @cfg {Boolean} animate
30500 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30505 * @cfg {String} title
30506 * Title text to display (defaults to ''). This can be any valid HTML markup.
30510 * @cfg {String} text
30511 * Body text to display (defaults to ''). This can be any valid HTML markup.
30515 * @cfg {String} cls
30516 * A CSS class to apply to the base quick tip element (defaults to '').
30520 * @cfg {Number} width
30521 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30522 * minWidth or maxWidth.
30527 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30528 * or display QuickTips in a page.
30531 tm = Roo.QuickTips;
30532 cfg = tm.tagConfig;
30534 if(!Roo.isReady){ // allow calling of init() before onReady
30535 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30538 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30539 el.fxDefaults = {stopFx: true};
30540 // maximum custom styling
30541 //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>');
30542 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>');
30543 tipTitle = el.child('h3');
30544 tipTitle.enableDisplayMode("block");
30545 tipBody = el.child('div.x-tip-bd');
30546 tipBodyText = el.child('div.x-tip-bd-inner');
30547 //bdLeft = el.child('div.x-tip-bd-left');
30548 //bdRight = el.child('div.x-tip-bd-right');
30549 close = el.child('div.x-tip-close');
30550 close.enableDisplayMode("block");
30551 close.on("click", hide);
30552 var d = Roo.get(document);
30553 d.on("mousedown", onDown);
30554 d.on("mouseover", onOver);
30555 d.on("mouseout", onOut);
30556 d.on("mousemove", onMove);
30557 esc = d.addKeyListener(27, hide);
30560 dd = el.initDD("default", null, {
30561 onDrag : function(){
30565 dd.setHandleElId(tipTitle.id);
30574 * Configures a new quick tip instance and assigns it to a target element. The following config options
30577 Property Type Description
30578 ---------- --------------------- ------------------------------------------------------------------------
30579 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30581 * @param {Object} config The config object
30583 register : function(config){
30584 var cs = config instanceof Array ? config : arguments;
30585 for(var i = 0, len = cs.length; i < len; i++) {
30587 var target = c.target;
30589 if(target instanceof Array){
30590 for(var j = 0, jlen = target.length; j < jlen; j++){
30591 tagEls[target[j]] = c;
30594 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30601 * Removes this quick tip from its element and destroys it.
30602 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30604 unregister : function(el){
30605 delete tagEls[Roo.id(el)];
30609 * Enable this quick tip.
30611 enable : function(){
30612 if(inited && disabled){
30614 if(locks.length < 1){
30621 * Disable this quick tip.
30623 disable : function(){
30625 clearTimeout(showProc);
30626 clearTimeout(hideProc);
30627 clearTimeout(dismissProc);
30635 * Returns true if the quick tip is enabled, else false.
30637 isEnabled : function(){
30644 attribute : "qtip",
30654 // backwards compat
30655 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30657 * Ext JS Library 1.1.1
30658 * Copyright(c) 2006-2007, Ext JS, LLC.
30660 * Originally Released Under LGPL - original licence link has changed is not relivant.
30663 * <script type="text/javascript">
30668 * @class Roo.tree.TreePanel
30669 * @extends Roo.data.Tree
30671 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30672 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30673 * @cfg {Boolean} enableDD true to enable drag and drop
30674 * @cfg {Boolean} enableDrag true to enable just drag
30675 * @cfg {Boolean} enableDrop true to enable just drop
30676 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30677 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30678 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30679 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30680 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30681 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30682 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30683 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30684 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30685 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30686 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30687 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30688 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30689 * @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>
30690 * @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>
30693 * @param {String/HTMLElement/Element} el The container element
30694 * @param {Object} config
30696 Roo.tree.TreePanel = function(el, config){
30698 var loader = false;
30700 root = config.root;
30701 delete config.root;
30703 if (config.loader) {
30704 loader = config.loader;
30705 delete config.loader;
30708 Roo.apply(this, config);
30709 Roo.tree.TreePanel.superclass.constructor.call(this);
30710 this.el = Roo.get(el);
30711 this.el.addClass('x-tree');
30712 //console.log(root);
30714 this.setRootNode( Roo.factory(root, Roo.tree));
30717 this.loader = Roo.factory(loader, Roo.tree);
30720 * Read-only. The id of the container element becomes this TreePanel's id.
30722 this.id = this.el.id;
30725 * @event beforeload
30726 * Fires before a node is loaded, return false to cancel
30727 * @param {Node} node The node being loaded
30729 "beforeload" : true,
30732 * Fires when a node is loaded
30733 * @param {Node} node The node that was loaded
30737 * @event textchange
30738 * Fires when the text for a node is changed
30739 * @param {Node} node The node
30740 * @param {String} text The new text
30741 * @param {String} oldText The old text
30743 "textchange" : true,
30745 * @event beforeexpand
30746 * Fires before a node is expanded, return false to cancel.
30747 * @param {Node} node The node
30748 * @param {Boolean} deep
30749 * @param {Boolean} anim
30751 "beforeexpand" : true,
30753 * @event beforecollapse
30754 * Fires before a node is collapsed, return false to cancel.
30755 * @param {Node} node The node
30756 * @param {Boolean} deep
30757 * @param {Boolean} anim
30759 "beforecollapse" : true,
30762 * Fires when a node is expanded
30763 * @param {Node} node The node
30767 * @event disabledchange
30768 * Fires when the disabled status of a node changes
30769 * @param {Node} node The node
30770 * @param {Boolean} disabled
30772 "disabledchange" : true,
30775 * Fires when a node is collapsed
30776 * @param {Node} node The node
30780 * @event beforeclick
30781 * Fires before click processing on a node. Return false to cancel the default action.
30782 * @param {Node} node The node
30783 * @param {Roo.EventObject} e The event object
30785 "beforeclick":true,
30787 * @event checkchange
30788 * Fires when a node with a checkbox's checked property changes
30789 * @param {Node} this This node
30790 * @param {Boolean} checked
30792 "checkchange":true,
30795 * Fires when a node is clicked
30796 * @param {Node} node The node
30797 * @param {Roo.EventObject} e The event object
30802 * Fires when a node is double clicked
30803 * @param {Node} node The node
30804 * @param {Roo.EventObject} e The event object
30808 * @event contextmenu
30809 * Fires when a node is right clicked
30810 * @param {Node} node The node
30811 * @param {Roo.EventObject} e The event object
30813 "contextmenu":true,
30815 * @event beforechildrenrendered
30816 * Fires right before the child nodes for a node are rendered
30817 * @param {Node} node The node
30819 "beforechildrenrendered":true,
30822 * Fires when a node starts being dragged
30823 * @param {Roo.tree.TreePanel} this
30824 * @param {Roo.tree.TreeNode} node
30825 * @param {event} e The raw browser event
30827 "startdrag" : true,
30830 * Fires when a drag operation is complete
30831 * @param {Roo.tree.TreePanel} this
30832 * @param {Roo.tree.TreeNode} node
30833 * @param {event} e The raw browser event
30838 * Fires when a dragged node is dropped on a valid DD target
30839 * @param {Roo.tree.TreePanel} this
30840 * @param {Roo.tree.TreeNode} node
30841 * @param {DD} dd The dd it was dropped on
30842 * @param {event} e The raw browser event
30846 * @event beforenodedrop
30847 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30848 * passed to handlers has the following properties:<br />
30849 * <ul style="padding:5px;padding-left:16px;">
30850 * <li>tree - The TreePanel</li>
30851 * <li>target - The node being targeted for the drop</li>
30852 * <li>data - The drag data from the drag source</li>
30853 * <li>point - The point of the drop - append, above or below</li>
30854 * <li>source - The drag source</li>
30855 * <li>rawEvent - Raw mouse event</li>
30856 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30857 * to be inserted by setting them on this object.</li>
30858 * <li>cancel - Set this to true to cancel the drop.</li>
30860 * @param {Object} dropEvent
30862 "beforenodedrop" : true,
30865 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30866 * passed to handlers has the following properties:<br />
30867 * <ul style="padding:5px;padding-left:16px;">
30868 * <li>tree - The TreePanel</li>
30869 * <li>target - The node being targeted for the drop</li>
30870 * <li>data - The drag data from the drag source</li>
30871 * <li>point - The point of the drop - append, above or below</li>
30872 * <li>source - The drag source</li>
30873 * <li>rawEvent - Raw mouse event</li>
30874 * <li>dropNode - Dropped node(s).</li>
30876 * @param {Object} dropEvent
30880 * @event nodedragover
30881 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30882 * passed to handlers has the following properties:<br />
30883 * <ul style="padding:5px;padding-left:16px;">
30884 * <li>tree - The TreePanel</li>
30885 * <li>target - The node being targeted for the drop</li>
30886 * <li>data - The drag data from the drag source</li>
30887 * <li>point - The point of the drop - append, above or below</li>
30888 * <li>source - The drag source</li>
30889 * <li>rawEvent - Raw mouse event</li>
30890 * <li>dropNode - Drop node(s) provided by the source.</li>
30891 * <li>cancel - Set this to true to signal drop not allowed.</li>
30893 * @param {Object} dragOverEvent
30895 "nodedragover" : true
30898 if(this.singleExpand){
30899 this.on("beforeexpand", this.restrictExpand, this);
30902 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30903 rootVisible : true,
30904 animate: Roo.enableFx,
30907 hlDrop : Roo.enableFx,
30911 rendererTip: false,
30913 restrictExpand : function(node){
30914 var p = node.parentNode;
30916 if(p.expandedChild && p.expandedChild.parentNode == p){
30917 p.expandedChild.collapse();
30919 p.expandedChild = node;
30923 // private override
30924 setRootNode : function(node){
30925 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30926 if(!this.rootVisible){
30927 node.ui = new Roo.tree.RootTreeNodeUI(node);
30933 * Returns the container element for this TreePanel
30935 getEl : function(){
30940 * Returns the default TreeLoader for this TreePanel
30942 getLoader : function(){
30943 return this.loader;
30949 expandAll : function(){
30950 this.root.expand(true);
30954 * Collapse all nodes
30956 collapseAll : function(){
30957 this.root.collapse(true);
30961 * Returns the selection model used by this TreePanel
30963 getSelectionModel : function(){
30964 if(!this.selModel){
30965 this.selModel = new Roo.tree.DefaultSelectionModel();
30967 return this.selModel;
30971 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30972 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30973 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30976 getChecked : function(a, startNode){
30977 startNode = startNode || this.root;
30979 var f = function(){
30980 if(this.attributes.checked){
30981 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30984 startNode.cascade(f);
30989 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30990 * @param {String} path
30991 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30992 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30993 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30995 expandPath : function(path, attr, callback){
30996 attr = attr || "id";
30997 var keys = path.split(this.pathSeparator);
30998 var curNode = this.root;
30999 if(curNode.attributes[attr] != keys[1]){ // invalid root
31001 callback(false, null);
31006 var f = function(){
31007 if(++index == keys.length){
31009 callback(true, curNode);
31013 var c = curNode.findChild(attr, keys[index]);
31016 callback(false, curNode);
31021 c.expand(false, false, f);
31023 curNode.expand(false, false, f);
31027 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31028 * @param {String} path
31029 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31030 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31031 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31033 selectPath : function(path, attr, callback){
31034 attr = attr || "id";
31035 var keys = path.split(this.pathSeparator);
31036 var v = keys.pop();
31037 if(keys.length > 0){
31038 var f = function(success, node){
31039 if(success && node){
31040 var n = node.findChild(attr, v);
31046 }else if(callback){
31047 callback(false, n);
31051 callback(false, n);
31055 this.expandPath(keys.join(this.pathSeparator), attr, f);
31057 this.root.select();
31059 callback(true, this.root);
31064 getTreeEl : function(){
31069 * Trigger rendering of this TreePanel
31071 render : function(){
31072 if (this.innerCt) {
31073 return this; // stop it rendering more than once!!
31076 this.innerCt = this.el.createChild({tag:"ul",
31077 cls:"x-tree-root-ct " +
31078 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31080 if(this.containerScroll){
31081 Roo.dd.ScrollManager.register(this.el);
31083 if((this.enableDD || this.enableDrop) && !this.dropZone){
31085 * The dropZone used by this tree if drop is enabled
31086 * @type Roo.tree.TreeDropZone
31088 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31089 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31092 if((this.enableDD || this.enableDrag) && !this.dragZone){
31094 * The dragZone used by this tree if drag is enabled
31095 * @type Roo.tree.TreeDragZone
31097 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31098 ddGroup: this.ddGroup || "TreeDD",
31099 scroll: this.ddScroll
31102 this.getSelectionModel().init(this);
31104 console.log("ROOT not set in tree");
31107 this.root.render();
31108 if(!this.rootVisible){
31109 this.root.renderChildren();
31115 * Ext JS Library 1.1.1
31116 * Copyright(c) 2006-2007, Ext JS, LLC.
31118 * Originally Released Under LGPL - original licence link has changed is not relivant.
31121 * <script type="text/javascript">
31126 * @class Roo.tree.DefaultSelectionModel
31127 * @extends Roo.util.Observable
31128 * The default single selection for a TreePanel.
31130 Roo.tree.DefaultSelectionModel = function(){
31131 this.selNode = null;
31135 * @event selectionchange
31136 * Fires when the selected node changes
31137 * @param {DefaultSelectionModel} this
31138 * @param {TreeNode} node the new selection
31140 "selectionchange" : true,
31143 * @event beforeselect
31144 * Fires before the selected node changes, return false to cancel the change
31145 * @param {DefaultSelectionModel} this
31146 * @param {TreeNode} node the new selection
31147 * @param {TreeNode} node the old selection
31149 "beforeselect" : true
31153 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31154 init : function(tree){
31156 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31157 tree.on("click", this.onNodeClick, this);
31160 onNodeClick : function(node, e){
31161 if (e.ctrlKey && this.selNode == node) {
31162 this.unselect(node);
31170 * @param {TreeNode} node The node to select
31171 * @return {TreeNode} The selected node
31173 select : function(node){
31174 var last = this.selNode;
31175 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31177 last.ui.onSelectedChange(false);
31179 this.selNode = node;
31180 node.ui.onSelectedChange(true);
31181 this.fireEvent("selectionchange", this, node, last);
31188 * @param {TreeNode} node The node to unselect
31190 unselect : function(node){
31191 if(this.selNode == node){
31192 this.clearSelections();
31197 * Clear all selections
31199 clearSelections : function(){
31200 var n = this.selNode;
31202 n.ui.onSelectedChange(false);
31203 this.selNode = null;
31204 this.fireEvent("selectionchange", this, null);
31210 * Get the selected node
31211 * @return {TreeNode} The selected node
31213 getSelectedNode : function(){
31214 return this.selNode;
31218 * Returns true if the node is selected
31219 * @param {TreeNode} node The node to check
31220 * @return {Boolean}
31222 isSelected : function(node){
31223 return this.selNode == node;
31227 * Selects the node above the selected node in the tree, intelligently walking the nodes
31228 * @return TreeNode The new selection
31230 selectPrevious : function(){
31231 var s = this.selNode || this.lastSelNode;
31235 var ps = s.previousSibling;
31237 if(!ps.isExpanded() || ps.childNodes.length < 1){
31238 return this.select(ps);
31240 var lc = ps.lastChild;
31241 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31244 return this.select(lc);
31246 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31247 return this.select(s.parentNode);
31253 * Selects the node above the selected node in the tree, intelligently walking the nodes
31254 * @return TreeNode The new selection
31256 selectNext : function(){
31257 var s = this.selNode || this.lastSelNode;
31261 if(s.firstChild && s.isExpanded()){
31262 return this.select(s.firstChild);
31263 }else if(s.nextSibling){
31264 return this.select(s.nextSibling);
31265 }else if(s.parentNode){
31267 s.parentNode.bubble(function(){
31268 if(this.nextSibling){
31269 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31278 onKeyDown : function(e){
31279 var s = this.selNode || this.lastSelNode;
31280 // undesirable, but required
31285 var k = e.getKey();
31293 this.selectPrevious();
31296 e.preventDefault();
31297 if(s.hasChildNodes()){
31298 if(!s.isExpanded()){
31300 }else if(s.firstChild){
31301 this.select(s.firstChild, e);
31306 e.preventDefault();
31307 if(s.hasChildNodes() && s.isExpanded()){
31309 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31310 this.select(s.parentNode, e);
31318 * @class Roo.tree.MultiSelectionModel
31319 * @extends Roo.util.Observable
31320 * Multi selection for a TreePanel.
31322 Roo.tree.MultiSelectionModel = function(){
31323 this.selNodes = [];
31327 * @event selectionchange
31328 * Fires when the selected nodes change
31329 * @param {MultiSelectionModel} this
31330 * @param {Array} nodes Array of the selected nodes
31332 "selectionchange" : true
31336 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31337 init : function(tree){
31339 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31340 tree.on("click", this.onNodeClick, this);
31343 onNodeClick : function(node, e){
31344 this.select(node, e, e.ctrlKey);
31349 * @param {TreeNode} node The node to select
31350 * @param {EventObject} e (optional) An event associated with the selection
31351 * @param {Boolean} keepExisting True to retain existing selections
31352 * @return {TreeNode} The selected node
31354 select : function(node, e, keepExisting){
31355 if(keepExisting !== true){
31356 this.clearSelections(true);
31358 if(this.isSelected(node)){
31359 this.lastSelNode = node;
31362 this.selNodes.push(node);
31363 this.selMap[node.id] = node;
31364 this.lastSelNode = node;
31365 node.ui.onSelectedChange(true);
31366 this.fireEvent("selectionchange", this, this.selNodes);
31372 * @param {TreeNode} node The node to unselect
31374 unselect : function(node){
31375 if(this.selMap[node.id]){
31376 node.ui.onSelectedChange(false);
31377 var sn = this.selNodes;
31380 index = sn.indexOf(node);
31382 for(var i = 0, len = sn.length; i < len; i++){
31390 this.selNodes.splice(index, 1);
31392 delete this.selMap[node.id];
31393 this.fireEvent("selectionchange", this, this.selNodes);
31398 * Clear all selections
31400 clearSelections : function(suppressEvent){
31401 var sn = this.selNodes;
31403 for(var i = 0, len = sn.length; i < len; i++){
31404 sn[i].ui.onSelectedChange(false);
31406 this.selNodes = [];
31408 if(suppressEvent !== true){
31409 this.fireEvent("selectionchange", this, this.selNodes);
31415 * Returns true if the node is selected
31416 * @param {TreeNode} node The node to check
31417 * @return {Boolean}
31419 isSelected : function(node){
31420 return this.selMap[node.id] ? true : false;
31424 * Returns an array of the selected nodes
31427 getSelectedNodes : function(){
31428 return this.selNodes;
31431 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31433 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31435 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31438 * Ext JS Library 1.1.1
31439 * Copyright(c) 2006-2007, Ext JS, LLC.
31441 * Originally Released Under LGPL - original licence link has changed is not relivant.
31444 * <script type="text/javascript">
31448 * @class Roo.tree.TreeNode
31449 * @extends Roo.data.Node
31450 * @cfg {String} text The text for this node
31451 * @cfg {Boolean} expanded true to start the node expanded
31452 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31453 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31454 * @cfg {Boolean} disabled true to start the node disabled
31455 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31456 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31457 * @cfg {String} cls A css class to be added to the node
31458 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31459 * @cfg {String} href URL of the link used for the node (defaults to #)
31460 * @cfg {String} hrefTarget target frame for the link
31461 * @cfg {String} qtip An Ext QuickTip for the node
31462 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31463 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31464 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31465 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31466 * (defaults to undefined with no checkbox rendered)
31468 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31470 Roo.tree.TreeNode = function(attributes){
31471 attributes = attributes || {};
31472 if(typeof attributes == "string"){
31473 attributes = {text: attributes};
31475 this.childrenRendered = false;
31476 this.rendered = false;
31477 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31478 this.expanded = attributes.expanded === true;
31479 this.isTarget = attributes.isTarget !== false;
31480 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31481 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31484 * Read-only. The text for this node. To change it use setText().
31487 this.text = attributes.text;
31489 * True if this node is disabled.
31492 this.disabled = attributes.disabled === true;
31496 * @event textchange
31497 * Fires when the text for this node is changed
31498 * @param {Node} this This node
31499 * @param {String} text The new text
31500 * @param {String} oldText The old text
31502 "textchange" : true,
31504 * @event beforeexpand
31505 * Fires before this node is expanded, return false to cancel.
31506 * @param {Node} this This node
31507 * @param {Boolean} deep
31508 * @param {Boolean} anim
31510 "beforeexpand" : true,
31512 * @event beforecollapse
31513 * Fires before this node is collapsed, return false to cancel.
31514 * @param {Node} this This node
31515 * @param {Boolean} deep
31516 * @param {Boolean} anim
31518 "beforecollapse" : true,
31521 * Fires when this node is expanded
31522 * @param {Node} this This node
31526 * @event disabledchange
31527 * Fires when the disabled status of this node changes
31528 * @param {Node} this This node
31529 * @param {Boolean} disabled
31531 "disabledchange" : true,
31534 * Fires when this node is collapsed
31535 * @param {Node} this This node
31539 * @event beforeclick
31540 * Fires before click processing. Return false to cancel the default action.
31541 * @param {Node} this This node
31542 * @param {Roo.EventObject} e The event object
31544 "beforeclick":true,
31546 * @event checkchange
31547 * Fires when a node with a checkbox's checked property changes
31548 * @param {Node} this This node
31549 * @param {Boolean} checked
31551 "checkchange":true,
31554 * Fires when this node is clicked
31555 * @param {Node} this This node
31556 * @param {Roo.EventObject} e The event object
31561 * Fires when this node is double clicked
31562 * @param {Node} this This node
31563 * @param {Roo.EventObject} e The event object
31567 * @event contextmenu
31568 * Fires when this node is right clicked
31569 * @param {Node} this This node
31570 * @param {Roo.EventObject} e The event object
31572 "contextmenu":true,
31574 * @event beforechildrenrendered
31575 * Fires right before the child nodes for this node are rendered
31576 * @param {Node} this This node
31578 "beforechildrenrendered":true
31581 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31584 * Read-only. The UI for this node
31587 this.ui = new uiClass(this);
31589 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31590 preventHScroll: true,
31592 * Returns true if this node is expanded
31593 * @return {Boolean}
31595 isExpanded : function(){
31596 return this.expanded;
31600 * Returns the UI object for this node
31601 * @return {TreeNodeUI}
31603 getUI : function(){
31607 // private override
31608 setFirstChild : function(node){
31609 var of = this.firstChild;
31610 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31611 if(this.childrenRendered && of && node != of){
31612 of.renderIndent(true, true);
31615 this.renderIndent(true, true);
31619 // private override
31620 setLastChild : function(node){
31621 var ol = this.lastChild;
31622 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31623 if(this.childrenRendered && ol && node != ol){
31624 ol.renderIndent(true, true);
31627 this.renderIndent(true, true);
31631 // these methods are overridden to provide lazy rendering support
31632 // private override
31633 appendChild : function(){
31634 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31635 if(node && this.childrenRendered){
31638 this.ui.updateExpandIcon();
31642 // private override
31643 removeChild : function(node){
31644 this.ownerTree.getSelectionModel().unselect(node);
31645 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31646 // if it's been rendered remove dom node
31647 if(this.childrenRendered){
31650 if(this.childNodes.length < 1){
31651 this.collapse(false, false);
31653 this.ui.updateExpandIcon();
31655 if(!this.firstChild) {
31656 this.childrenRendered = false;
31661 // private override
31662 insertBefore : function(node, refNode){
31663 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31664 if(newNode && refNode && this.childrenRendered){
31667 this.ui.updateExpandIcon();
31672 * Sets the text for this node
31673 * @param {String} text
31675 setText : function(text){
31676 var oldText = this.text;
31678 this.attributes.text = text;
31679 if(this.rendered){ // event without subscribing
31680 this.ui.onTextChange(this, text, oldText);
31682 this.fireEvent("textchange", this, text, oldText);
31686 * Triggers selection of this node
31688 select : function(){
31689 this.getOwnerTree().getSelectionModel().select(this);
31693 * Triggers deselection of this node
31695 unselect : function(){
31696 this.getOwnerTree().getSelectionModel().unselect(this);
31700 * Returns true if this node is selected
31701 * @return {Boolean}
31703 isSelected : function(){
31704 return this.getOwnerTree().getSelectionModel().isSelected(this);
31708 * Expand this node.
31709 * @param {Boolean} deep (optional) True to expand all children as well
31710 * @param {Boolean} anim (optional) false to cancel the default animation
31711 * @param {Function} callback (optional) A callback to be called when
31712 * expanding this node completes (does not wait for deep expand to complete).
31713 * Called with 1 parameter, this node.
31715 expand : function(deep, anim, callback){
31716 if(!this.expanded){
31717 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31720 if(!this.childrenRendered){
31721 this.renderChildren();
31723 this.expanded = true;
31724 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31725 this.ui.animExpand(function(){
31726 this.fireEvent("expand", this);
31727 if(typeof callback == "function"){
31731 this.expandChildNodes(true);
31733 }.createDelegate(this));
31737 this.fireEvent("expand", this);
31738 if(typeof callback == "function"){
31743 if(typeof callback == "function"){
31748 this.expandChildNodes(true);
31752 isHiddenRoot : function(){
31753 return this.isRoot && !this.getOwnerTree().rootVisible;
31757 * Collapse this node.
31758 * @param {Boolean} deep (optional) True to collapse all children as well
31759 * @param {Boolean} anim (optional) false to cancel the default animation
31761 collapse : function(deep, anim){
31762 if(this.expanded && !this.isHiddenRoot()){
31763 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31766 this.expanded = false;
31767 if((this.getOwnerTree().animate && anim !== false) || anim){
31768 this.ui.animCollapse(function(){
31769 this.fireEvent("collapse", this);
31771 this.collapseChildNodes(true);
31773 }.createDelegate(this));
31776 this.ui.collapse();
31777 this.fireEvent("collapse", this);
31781 var cs = this.childNodes;
31782 for(var i = 0, len = cs.length; i < len; i++) {
31783 cs[i].collapse(true, false);
31789 delayedExpand : function(delay){
31790 if(!this.expandProcId){
31791 this.expandProcId = this.expand.defer(delay, this);
31796 cancelExpand : function(){
31797 if(this.expandProcId){
31798 clearTimeout(this.expandProcId);
31800 this.expandProcId = false;
31804 * Toggles expanded/collapsed state of the node
31806 toggle : function(){
31815 * Ensures all parent nodes are expanded
31817 ensureVisible : function(callback){
31818 var tree = this.getOwnerTree();
31819 tree.expandPath(this.parentNode.getPath(), false, function(){
31820 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31821 Roo.callback(callback);
31822 }.createDelegate(this));
31826 * Expand all child nodes
31827 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31829 expandChildNodes : function(deep){
31830 var cs = this.childNodes;
31831 for(var i = 0, len = cs.length; i < len; i++) {
31832 cs[i].expand(deep);
31837 * Collapse all child nodes
31838 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31840 collapseChildNodes : function(deep){
31841 var cs = this.childNodes;
31842 for(var i = 0, len = cs.length; i < len; i++) {
31843 cs[i].collapse(deep);
31848 * Disables this node
31850 disable : function(){
31851 this.disabled = true;
31853 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31854 this.ui.onDisableChange(this, true);
31856 this.fireEvent("disabledchange", this, true);
31860 * Enables this node
31862 enable : function(){
31863 this.disabled = false;
31864 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31865 this.ui.onDisableChange(this, false);
31867 this.fireEvent("disabledchange", this, false);
31871 renderChildren : function(suppressEvent){
31872 if(suppressEvent !== false){
31873 this.fireEvent("beforechildrenrendered", this);
31875 var cs = this.childNodes;
31876 for(var i = 0, len = cs.length; i < len; i++){
31877 cs[i].render(true);
31879 this.childrenRendered = true;
31883 sort : function(fn, scope){
31884 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31885 if(this.childrenRendered){
31886 var cs = this.childNodes;
31887 for(var i = 0, len = cs.length; i < len; i++){
31888 cs[i].render(true);
31894 render : function(bulkRender){
31895 this.ui.render(bulkRender);
31896 if(!this.rendered){
31897 this.rendered = true;
31899 this.expanded = false;
31900 this.expand(false, false);
31906 renderIndent : function(deep, refresh){
31908 this.ui.childIndent = null;
31910 this.ui.renderIndent();
31911 if(deep === true && this.childrenRendered){
31912 var cs = this.childNodes;
31913 for(var i = 0, len = cs.length; i < len; i++){
31914 cs[i].renderIndent(true, refresh);
31920 * Ext JS Library 1.1.1
31921 * Copyright(c) 2006-2007, Ext JS, LLC.
31923 * Originally Released Under LGPL - original licence link has changed is not relivant.
31926 * <script type="text/javascript">
31930 * @class Roo.tree.AsyncTreeNode
31931 * @extends Roo.tree.TreeNode
31932 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31934 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31936 Roo.tree.AsyncTreeNode = function(config){
31937 this.loaded = false;
31938 this.loading = false;
31939 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31941 * @event beforeload
31942 * Fires before this node is loaded, return false to cancel
31943 * @param {Node} this This node
31945 this.addEvents({'beforeload':true, 'load': true});
31948 * Fires when this node is loaded
31949 * @param {Node} this This node
31952 * The loader used by this node (defaults to using the tree's defined loader)
31957 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31958 expand : function(deep, anim, callback){
31959 if(this.loading){ // if an async load is already running, waiting til it's done
31961 var f = function(){
31962 if(!this.loading){ // done loading
31963 clearInterval(timer);
31964 this.expand(deep, anim, callback);
31966 }.createDelegate(this);
31967 timer = setInterval(f, 200);
31971 if(this.fireEvent("beforeload", this) === false){
31974 this.loading = true;
31975 this.ui.beforeLoad(this);
31976 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31978 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31982 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31986 * Returns true if this node is currently loading
31987 * @return {Boolean}
31989 isLoading : function(){
31990 return this.loading;
31993 loadComplete : function(deep, anim, callback){
31994 this.loading = false;
31995 this.loaded = true;
31996 this.ui.afterLoad(this);
31997 this.fireEvent("load", this);
31998 this.expand(deep, anim, callback);
32002 * Returns true if this node has been loaded
32003 * @return {Boolean}
32005 isLoaded : function(){
32006 return this.loaded;
32009 hasChildNodes : function(){
32010 if(!this.isLeaf() && !this.loaded){
32013 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32018 * Trigger a reload for this node
32019 * @param {Function} callback
32021 reload : function(callback){
32022 this.collapse(false, false);
32023 while(this.firstChild){
32024 this.removeChild(this.firstChild);
32026 this.childrenRendered = false;
32027 this.loaded = false;
32028 if(this.isHiddenRoot()){
32029 this.expanded = false;
32031 this.expand(false, false, callback);
32035 * Ext JS Library 1.1.1
32036 * Copyright(c) 2006-2007, Ext JS, LLC.
32038 * Originally Released Under LGPL - original licence link has changed is not relivant.
32041 * <script type="text/javascript">
32045 * @class Roo.tree.TreeNodeUI
32047 * @param {Object} node The node to render
32048 * The TreeNode UI implementation is separate from the
32049 * tree implementation. Unless you are customizing the tree UI,
32050 * you should never have to use this directly.
32052 Roo.tree.TreeNodeUI = function(node){
32054 this.rendered = false;
32055 this.animating = false;
32056 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32059 Roo.tree.TreeNodeUI.prototype = {
32060 removeChild : function(node){
32062 this.ctNode.removeChild(node.ui.getEl());
32066 beforeLoad : function(){
32067 this.addClass("x-tree-node-loading");
32070 afterLoad : function(){
32071 this.removeClass("x-tree-node-loading");
32074 onTextChange : function(node, text, oldText){
32076 this.textNode.innerHTML = text;
32080 onDisableChange : function(node, state){
32081 this.disabled = state;
32083 this.addClass("x-tree-node-disabled");
32085 this.removeClass("x-tree-node-disabled");
32089 onSelectedChange : function(state){
32092 this.addClass("x-tree-selected");
32095 this.removeClass("x-tree-selected");
32099 onMove : function(tree, node, oldParent, newParent, index, refNode){
32100 this.childIndent = null;
32102 var targetNode = newParent.ui.getContainer();
32103 if(!targetNode){//target not rendered
32104 this.holder = document.createElement("div");
32105 this.holder.appendChild(this.wrap);
32108 var insertBefore = refNode ? refNode.ui.getEl() : null;
32110 targetNode.insertBefore(this.wrap, insertBefore);
32112 targetNode.appendChild(this.wrap);
32114 this.node.renderIndent(true);
32118 addClass : function(cls){
32120 Roo.fly(this.elNode).addClass(cls);
32124 removeClass : function(cls){
32126 Roo.fly(this.elNode).removeClass(cls);
32130 remove : function(){
32132 this.holder = document.createElement("div");
32133 this.holder.appendChild(this.wrap);
32137 fireEvent : function(){
32138 return this.node.fireEvent.apply(this.node, arguments);
32141 initEvents : function(){
32142 this.node.on("move", this.onMove, this);
32143 var E = Roo.EventManager;
32144 var a = this.anchor;
32146 var el = Roo.fly(a, '_treeui');
32148 if(Roo.isOpera){ // opera render bug ignores the CSS
32149 el.setStyle("text-decoration", "none");
32152 el.on("click", this.onClick, this);
32153 el.on("dblclick", this.onDblClick, this);
32156 Roo.EventManager.on(this.checkbox,
32157 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32160 el.on("contextmenu", this.onContextMenu, this);
32162 var icon = Roo.fly(this.iconNode);
32163 icon.on("click", this.onClick, this);
32164 icon.on("dblclick", this.onDblClick, this);
32165 icon.on("contextmenu", this.onContextMenu, this);
32166 E.on(this.ecNode, "click", this.ecClick, this, true);
32168 if(this.node.disabled){
32169 this.addClass("x-tree-node-disabled");
32171 if(this.node.hidden){
32172 this.addClass("x-tree-node-disabled");
32174 var ot = this.node.getOwnerTree();
32175 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32176 if(dd && (!this.node.isRoot || ot.rootVisible)){
32177 Roo.dd.Registry.register(this.elNode, {
32179 handles: this.getDDHandles(),
32185 getDDHandles : function(){
32186 return [this.iconNode, this.textNode];
32191 this.wrap.style.display = "none";
32197 this.wrap.style.display = "";
32201 onContextMenu : function(e){
32202 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32203 e.preventDefault();
32205 this.fireEvent("contextmenu", this.node, e);
32209 onClick : function(e){
32214 if(this.fireEvent("beforeclick", this.node, e) !== false){
32215 if(!this.disabled && this.node.attributes.href){
32216 this.fireEvent("click", this.node, e);
32219 e.preventDefault();
32224 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32225 this.node.toggle();
32228 this.fireEvent("click", this.node, e);
32234 onDblClick : function(e){
32235 e.preventDefault();
32240 this.toggleCheck();
32242 if(!this.animating && this.node.hasChildNodes()){
32243 this.node.toggle();
32245 this.fireEvent("dblclick", this.node, e);
32248 onCheckChange : function(){
32249 var checked = this.checkbox.checked;
32250 this.node.attributes.checked = checked;
32251 this.fireEvent('checkchange', this.node, checked);
32254 ecClick : function(e){
32255 if(!this.animating && this.node.hasChildNodes()){
32256 this.node.toggle();
32260 startDrop : function(){
32261 this.dropping = true;
32264 // delayed drop so the click event doesn't get fired on a drop
32265 endDrop : function(){
32266 setTimeout(function(){
32267 this.dropping = false;
32268 }.createDelegate(this), 50);
32271 expand : function(){
32272 this.updateExpandIcon();
32273 this.ctNode.style.display = "";
32276 focus : function(){
32277 if(!this.node.preventHScroll){
32278 try{this.anchor.focus();
32280 }else if(!Roo.isIE){
32282 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32283 var l = noscroll.scrollLeft;
32284 this.anchor.focus();
32285 noscroll.scrollLeft = l;
32290 toggleCheck : function(value){
32291 var cb = this.checkbox;
32293 cb.checked = (value === undefined ? !cb.checked : value);
32299 this.anchor.blur();
32303 animExpand : function(callback){
32304 var ct = Roo.get(this.ctNode);
32306 if(!this.node.hasChildNodes()){
32307 this.updateExpandIcon();
32308 this.ctNode.style.display = "";
32309 Roo.callback(callback);
32312 this.animating = true;
32313 this.updateExpandIcon();
32316 callback : function(){
32317 this.animating = false;
32318 Roo.callback(callback);
32321 duration: this.node.ownerTree.duration || .25
32325 highlight : function(){
32326 var tree = this.node.getOwnerTree();
32327 Roo.fly(this.wrap).highlight(
32328 tree.hlColor || "C3DAF9",
32329 {endColor: tree.hlBaseColor}
32333 collapse : function(){
32334 this.updateExpandIcon();
32335 this.ctNode.style.display = "none";
32338 animCollapse : function(callback){
32339 var ct = Roo.get(this.ctNode);
32340 ct.enableDisplayMode('block');
32343 this.animating = true;
32344 this.updateExpandIcon();
32347 callback : function(){
32348 this.animating = false;
32349 Roo.callback(callback);
32352 duration: this.node.ownerTree.duration || .25
32356 getContainer : function(){
32357 return this.ctNode;
32360 getEl : function(){
32364 appendDDGhost : function(ghostNode){
32365 ghostNode.appendChild(this.elNode.cloneNode(true));
32368 getDDRepairXY : function(){
32369 return Roo.lib.Dom.getXY(this.iconNode);
32372 onRender : function(){
32376 render : function(bulkRender){
32377 var n = this.node, a = n.attributes;
32378 var targetNode = n.parentNode ?
32379 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32381 if(!this.rendered){
32382 this.rendered = true;
32384 this.renderElements(n, a, targetNode, bulkRender);
32387 if(this.textNode.setAttributeNS){
32388 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32390 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32393 this.textNode.setAttribute("ext:qtip", a.qtip);
32395 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32398 }else if(a.qtipCfg){
32399 a.qtipCfg.target = Roo.id(this.textNode);
32400 Roo.QuickTips.register(a.qtipCfg);
32403 if(!this.node.expanded){
32404 this.updateExpandIcon();
32407 if(bulkRender === true) {
32408 targetNode.appendChild(this.wrap);
32413 renderElements : function(n, a, targetNode, bulkRender){
32414 // add some indent caching, this helps performance when rendering a large tree
32415 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32416 var t = n.getOwnerTree();
32417 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32418 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32419 var cb = typeof a.checked == 'boolean';
32420 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32421 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32422 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32423 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32424 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32425 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32426 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32427 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32428 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32429 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32432 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32433 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32434 n.nextSibling.ui.getEl(), buf.join(""));
32436 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32439 this.elNode = this.wrap.childNodes[0];
32440 this.ctNode = this.wrap.childNodes[1];
32441 var cs = this.elNode.childNodes;
32442 this.indentNode = cs[0];
32443 this.ecNode = cs[1];
32444 this.iconNode = cs[2];
32447 this.checkbox = cs[3];
32450 this.anchor = cs[index];
32451 this.textNode = cs[index].firstChild;
32454 getAnchor : function(){
32455 return this.anchor;
32458 getTextEl : function(){
32459 return this.textNode;
32462 getIconEl : function(){
32463 return this.iconNode;
32466 isChecked : function(){
32467 return this.checkbox ? this.checkbox.checked : false;
32470 updateExpandIcon : function(){
32472 var n = this.node, c1, c2;
32473 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32474 var hasChild = n.hasChildNodes();
32478 c1 = "x-tree-node-collapsed";
32479 c2 = "x-tree-node-expanded";
32482 c1 = "x-tree-node-expanded";
32483 c2 = "x-tree-node-collapsed";
32486 this.removeClass("x-tree-node-leaf");
32487 this.wasLeaf = false;
32489 if(this.c1 != c1 || this.c2 != c2){
32490 Roo.fly(this.elNode).replaceClass(c1, c2);
32491 this.c1 = c1; this.c2 = c2;
32495 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32498 this.wasLeaf = true;
32501 var ecc = "x-tree-ec-icon "+cls;
32502 if(this.ecc != ecc){
32503 this.ecNode.className = ecc;
32509 getChildIndent : function(){
32510 if(!this.childIndent){
32514 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32516 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32518 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32523 this.childIndent = buf.join("");
32525 return this.childIndent;
32528 renderIndent : function(){
32531 var p = this.node.parentNode;
32533 indent = p.ui.getChildIndent();
32535 if(this.indentMarkup != indent){ // don't rerender if not required
32536 this.indentNode.innerHTML = indent;
32537 this.indentMarkup = indent;
32539 this.updateExpandIcon();
32544 Roo.tree.RootTreeNodeUI = function(){
32545 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32547 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32548 render : function(){
32549 if(!this.rendered){
32550 var targetNode = this.node.ownerTree.innerCt.dom;
32551 this.node.expanded = true;
32552 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32553 this.wrap = this.ctNode = targetNode.firstChild;
32556 collapse : function(){
32558 expand : function(){
32562 * Ext JS Library 1.1.1
32563 * Copyright(c) 2006-2007, Ext JS, LLC.
32565 * Originally Released Under LGPL - original licence link has changed is not relivant.
32568 * <script type="text/javascript">
32571 * @class Roo.tree.TreeLoader
32572 * @extends Roo.util.Observable
32573 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32574 * nodes from a specified URL. The response must be a javascript Array definition
32575 * who's elements are node definition objects. eg:
32577 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32578 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32581 * A server request is sent, and child nodes are loaded only when a node is expanded.
32582 * The loading node's id is passed to the server under the parameter name "node" to
32583 * enable the server to produce the correct child nodes.
32585 * To pass extra parameters, an event handler may be attached to the "beforeload"
32586 * event, and the parameters specified in the TreeLoader's baseParams property:
32588 myTreeLoader.on("beforeload", function(treeLoader, node) {
32589 this.baseParams.category = node.attributes.category;
32592 * This would pass an HTTP parameter called "category" to the server containing
32593 * the value of the Node's "category" attribute.
32595 * Creates a new Treeloader.
32596 * @param {Object} config A config object containing config properties.
32598 Roo.tree.TreeLoader = function(config){
32599 this.baseParams = {};
32600 this.requestMethod = "POST";
32601 Roo.apply(this, config);
32606 * @event beforeload
32607 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32608 * @param {Object} This TreeLoader object.
32609 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32610 * @param {Object} callback The callback function specified in the {@link #load} call.
32615 * Fires when the node has been successfuly loaded.
32616 * @param {Object} This TreeLoader object.
32617 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32618 * @param {Object} response The response object containing the data from the server.
32622 * @event loadexception
32623 * Fires if the network request failed.
32624 * @param {Object} This TreeLoader object.
32625 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32626 * @param {Object} response The response object containing the data from the server.
32628 loadexception : true,
32631 * Fires before a node is created, enabling you to return custom Node types
32632 * @param {Object} This TreeLoader object.
32633 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32638 Roo.tree.TreeLoader.superclass.constructor.call(this);
32641 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32643 * @cfg {String} dataUrl The URL from which to request a Json string which
32644 * specifies an array of node definition object representing the child nodes
32648 * @cfg {Object} baseParams (optional) An object containing properties which
32649 * specify HTTP parameters to be passed to each request for child nodes.
32652 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32653 * created by this loader. If the attributes sent by the server have an attribute in this object,
32654 * they take priority.
32657 * @cfg {Object} uiProviders (optional) An object containing properties which
32659 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32660 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32661 * <i>uiProvider</i> attribute of a returned child node is a string rather
32662 * than a reference to a TreeNodeUI implementation, this that string value
32663 * is used as a property name in the uiProviders object. You can define the provider named
32664 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32669 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32670 * child nodes before loading.
32672 clearOnLoad : true,
32675 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32676 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32677 * Grid query { data : [ .....] }
32682 * @cfg {String} queryParam (optional)
32683 * Name of the query as it will be passed on the querystring (defaults to 'node')
32684 * eg. the request will be ?node=[id]
32691 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32692 * This is called automatically when a node is expanded, but may be used to reload
32693 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32694 * @param {Roo.tree.TreeNode} node
32695 * @param {Function} callback
32697 load : function(node, callback){
32698 if(this.clearOnLoad){
32699 while(node.firstChild){
32700 node.removeChild(node.firstChild);
32703 if(node.attributes.children){ // preloaded json children
32704 var cs = node.attributes.children;
32705 for(var i = 0, len = cs.length; i < len; i++){
32706 node.appendChild(this.createNode(cs[i]));
32708 if(typeof callback == "function"){
32711 }else if(this.dataUrl){
32712 this.requestData(node, callback);
32716 getParams: function(node){
32717 var buf = [], bp = this.baseParams;
32718 for(var key in bp){
32719 if(typeof bp[key] != "function"){
32720 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32723 var n = this.queryParam === false ? 'node' : this.queryParam;
32724 buf.push(n + "=", encodeURIComponent(node.id));
32725 return buf.join("");
32728 requestData : function(node, callback){
32729 if(this.fireEvent("beforeload", this, node, callback) !== false){
32730 this.transId = Roo.Ajax.request({
32731 method:this.requestMethod,
32732 url: this.dataUrl||this.url,
32733 success: this.handleResponse,
32734 failure: this.handleFailure,
32736 argument: {callback: callback, node: node},
32737 params: this.getParams(node)
32740 // if the load is cancelled, make sure we notify
32741 // the node that we are done
32742 if(typeof callback == "function"){
32748 isLoading : function(){
32749 return this.transId ? true : false;
32752 abort : function(){
32753 if(this.isLoading()){
32754 Roo.Ajax.abort(this.transId);
32759 createNode : function(attr){
32760 // apply baseAttrs, nice idea Corey!
32761 if(this.baseAttrs){
32762 Roo.applyIf(attr, this.baseAttrs);
32764 if(this.applyLoader !== false){
32765 attr.loader = this;
32767 // uiProvider = depreciated..
32769 if(typeof(attr.uiProvider) == 'string'){
32770 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32771 /** eval:var:attr */ eval(attr.uiProvider);
32773 if(typeof(this.uiProviders['default']) != 'undefined') {
32774 attr.uiProvider = this.uiProviders['default'];
32777 this.fireEvent('create', this, attr);
32779 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32781 new Roo.tree.TreeNode(attr) :
32782 new Roo.tree.AsyncTreeNode(attr));
32785 processResponse : function(response, node, callback){
32786 var json = response.responseText;
32789 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32790 if (this.root !== false) {
32794 for(var i = 0, len = o.length; i < len; i++){
32795 var n = this.createNode(o[i]);
32797 node.appendChild(n);
32800 if(typeof callback == "function"){
32801 callback(this, node);
32804 this.handleFailure(response);
32808 handleResponse : function(response){
32809 this.transId = false;
32810 var a = response.argument;
32811 this.processResponse(response, a.node, a.callback);
32812 this.fireEvent("load", this, a.node, response);
32815 handleFailure : function(response){
32816 this.transId = false;
32817 var a = response.argument;
32818 this.fireEvent("loadexception", this, a.node, response);
32819 if(typeof a.callback == "function"){
32820 a.callback(this, a.node);
32825 * Ext JS Library 1.1.1
32826 * Copyright(c) 2006-2007, Ext JS, LLC.
32828 * Originally Released Under LGPL - original licence link has changed is not relivant.
32831 * <script type="text/javascript">
32835 * @class Roo.tree.TreeFilter
32836 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32837 * @param {TreePanel} tree
32838 * @param {Object} config (optional)
32840 Roo.tree.TreeFilter = function(tree, config){
32842 this.filtered = {};
32843 Roo.apply(this, config);
32846 Roo.tree.TreeFilter.prototype = {
32853 * Filter the data by a specific attribute.
32854 * @param {String/RegExp} value Either string that the attribute value
32855 * should start with or a RegExp to test against the attribute
32856 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32857 * @param {TreeNode} startNode (optional) The node to start the filter at.
32859 filter : function(value, attr, startNode){
32860 attr = attr || "text";
32862 if(typeof value == "string"){
32863 var vlen = value.length;
32864 // auto clear empty filter
32865 if(vlen == 0 && this.clearBlank){
32869 value = value.toLowerCase();
32871 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32873 }else if(value.exec){ // regex?
32875 return value.test(n.attributes[attr]);
32878 throw 'Illegal filter type, must be string or regex';
32880 this.filterBy(f, null, startNode);
32884 * Filter by a function. The passed function will be called with each
32885 * node in the tree (or from the startNode). If the function returns true, the node is kept
32886 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32887 * @param {Function} fn The filter function
32888 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32890 filterBy : function(fn, scope, startNode){
32891 startNode = startNode || this.tree.root;
32892 if(this.autoClear){
32895 var af = this.filtered, rv = this.reverse;
32896 var f = function(n){
32897 if(n == startNode){
32903 var m = fn.call(scope || n, n);
32911 startNode.cascade(f);
32914 if(typeof id != "function"){
32916 if(n && n.parentNode){
32917 n.parentNode.removeChild(n);
32925 * Clears the current filter. Note: with the "remove" option
32926 * set a filter cannot be cleared.
32928 clear : function(){
32930 var af = this.filtered;
32932 if(typeof id != "function"){
32939 this.filtered = {};
32944 * Ext JS Library 1.1.1
32945 * Copyright(c) 2006-2007, Ext JS, LLC.
32947 * Originally Released Under LGPL - original licence link has changed is not relivant.
32950 * <script type="text/javascript">
32955 * @class Roo.tree.TreeSorter
32956 * Provides sorting of nodes in a TreePanel
32958 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32959 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32960 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32961 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32962 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32963 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32965 * @param {TreePanel} tree
32966 * @param {Object} config
32968 Roo.tree.TreeSorter = function(tree, config){
32969 Roo.apply(this, config);
32970 tree.on("beforechildrenrendered", this.doSort, this);
32971 tree.on("append", this.updateSort, this);
32972 tree.on("insert", this.updateSort, this);
32974 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32975 var p = this.property || "text";
32976 var sortType = this.sortType;
32977 var fs = this.folderSort;
32978 var cs = this.caseSensitive === true;
32979 var leafAttr = this.leafAttr || 'leaf';
32981 this.sortFn = function(n1, n2){
32983 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32986 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32990 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32991 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32993 return dsc ? +1 : -1;
32995 return dsc ? -1 : +1;
33002 Roo.tree.TreeSorter.prototype = {
33003 doSort : function(node){
33004 node.sort(this.sortFn);
33007 compareNodes : function(n1, n2){
33008 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33011 updateSort : function(tree, node){
33012 if(node.childrenRendered){
33013 this.doSort.defer(1, this, [node]);
33018 * Ext JS Library 1.1.1
33019 * Copyright(c) 2006-2007, Ext JS, LLC.
33021 * Originally Released Under LGPL - original licence link has changed is not relivant.
33024 * <script type="text/javascript">
33027 if(Roo.dd.DropZone){
33029 Roo.tree.TreeDropZone = function(tree, config){
33030 this.allowParentInsert = false;
33031 this.allowContainerDrop = false;
33032 this.appendOnly = false;
33033 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33035 this.lastInsertClass = "x-tree-no-status";
33036 this.dragOverData = {};
33039 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33040 ddGroup : "TreeDD",
33042 expandDelay : 1000,
33044 expandNode : function(node){
33045 if(node.hasChildNodes() && !node.isExpanded()){
33046 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33050 queueExpand : function(node){
33051 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33054 cancelExpand : function(){
33055 if(this.expandProcId){
33056 clearTimeout(this.expandProcId);
33057 this.expandProcId = false;
33061 isValidDropPoint : function(n, pt, dd, e, data){
33062 if(!n || !data){ return false; }
33063 var targetNode = n.node;
33064 var dropNode = data.node;
33065 // default drop rules
33066 if(!(targetNode && targetNode.isTarget && pt)){
33069 if(pt == "append" && targetNode.allowChildren === false){
33072 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33075 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33078 // reuse the object
33079 var overEvent = this.dragOverData;
33080 overEvent.tree = this.tree;
33081 overEvent.target = targetNode;
33082 overEvent.data = data;
33083 overEvent.point = pt;
33084 overEvent.source = dd;
33085 overEvent.rawEvent = e;
33086 overEvent.dropNode = dropNode;
33087 overEvent.cancel = false;
33088 var result = this.tree.fireEvent("nodedragover", overEvent);
33089 return overEvent.cancel === false && result !== false;
33092 getDropPoint : function(e, n, dd){
33095 return tn.allowChildren !== false ? "append" : false; // always append for root
33097 var dragEl = n.ddel;
33098 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33099 var y = Roo.lib.Event.getPageY(e);
33100 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33102 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33103 var noAppend = tn.allowChildren === false;
33104 if(this.appendOnly || tn.parentNode.allowChildren === false){
33105 return noAppend ? false : "append";
33107 var noBelow = false;
33108 if(!this.allowParentInsert){
33109 noBelow = tn.hasChildNodes() && tn.isExpanded();
33111 var q = (b - t) / (noAppend ? 2 : 3);
33112 if(y >= t && y < (t + q)){
33114 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33121 onNodeEnter : function(n, dd, e, data){
33122 this.cancelExpand();
33125 onNodeOver : function(n, dd, e, data){
33126 var pt = this.getDropPoint(e, n, dd);
33129 // auto node expand check
33130 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33131 this.queueExpand(node);
33132 }else if(pt != "append"){
33133 this.cancelExpand();
33136 // set the insert point style on the target node
33137 var returnCls = this.dropNotAllowed;
33138 if(this.isValidDropPoint(n, pt, dd, e, data)){
33143 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33144 cls = "x-tree-drag-insert-above";
33145 }else if(pt == "below"){
33146 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33147 cls = "x-tree-drag-insert-below";
33149 returnCls = "x-tree-drop-ok-append";
33150 cls = "x-tree-drag-append";
33152 if(this.lastInsertClass != cls){
33153 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33154 this.lastInsertClass = cls;
33161 onNodeOut : function(n, dd, e, data){
33162 this.cancelExpand();
33163 this.removeDropIndicators(n);
33166 onNodeDrop : function(n, dd, e, data){
33167 var point = this.getDropPoint(e, n, dd);
33168 var targetNode = n.node;
33169 targetNode.ui.startDrop();
33170 if(!this.isValidDropPoint(n, point, dd, e, data)){
33171 targetNode.ui.endDrop();
33174 // first try to find the drop node
33175 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33178 target: targetNode,
33183 dropNode: dropNode,
33186 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33187 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33188 targetNode.ui.endDrop();
33191 // allow target changing
33192 targetNode = dropEvent.target;
33193 if(point == "append" && !targetNode.isExpanded()){
33194 targetNode.expand(false, null, function(){
33195 this.completeDrop(dropEvent);
33196 }.createDelegate(this));
33198 this.completeDrop(dropEvent);
33203 completeDrop : function(de){
33204 var ns = de.dropNode, p = de.point, t = de.target;
33205 if(!(ns instanceof Array)){
33209 for(var i = 0, len = ns.length; i < len; i++){
33212 t.parentNode.insertBefore(n, t);
33213 }else if(p == "below"){
33214 t.parentNode.insertBefore(n, t.nextSibling);
33220 if(this.tree.hlDrop){
33224 this.tree.fireEvent("nodedrop", de);
33227 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33228 if(this.tree.hlDrop){
33229 dropNode.ui.focus();
33230 dropNode.ui.highlight();
33232 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33235 getTree : function(){
33239 removeDropIndicators : function(n){
33242 Roo.fly(el).removeClass([
33243 "x-tree-drag-insert-above",
33244 "x-tree-drag-insert-below",
33245 "x-tree-drag-append"]);
33246 this.lastInsertClass = "_noclass";
33250 beforeDragDrop : function(target, e, id){
33251 this.cancelExpand();
33255 afterRepair : function(data){
33256 if(data && Roo.enableFx){
33257 data.node.ui.highlight();
33266 * Ext JS Library 1.1.1
33267 * Copyright(c) 2006-2007, Ext JS, LLC.
33269 * Originally Released Under LGPL - original licence link has changed is not relivant.
33272 * <script type="text/javascript">
33276 if(Roo.dd.DragZone){
33277 Roo.tree.TreeDragZone = function(tree, config){
33278 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33282 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33283 ddGroup : "TreeDD",
33285 onBeforeDrag : function(data, e){
33287 return n && n.draggable && !n.disabled;
33290 onInitDrag : function(e){
33291 var data = this.dragData;
33292 this.tree.getSelectionModel().select(data.node);
33293 this.proxy.update("");
33294 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33295 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33298 getRepairXY : function(e, data){
33299 return data.node.ui.getDDRepairXY();
33302 onEndDrag : function(data, e){
33303 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33306 onValidDrop : function(dd, e, id){
33307 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33311 beforeInvalidDrop : function(e, id){
33312 // this scrolls the original position back into view
33313 var sm = this.tree.getSelectionModel();
33314 sm.clearSelections();
33315 sm.select(this.dragData.node);
33320 * Ext JS Library 1.1.1
33321 * Copyright(c) 2006-2007, Ext JS, LLC.
33323 * Originally Released Under LGPL - original licence link has changed is not relivant.
33326 * <script type="text/javascript">
33329 * @class Roo.tree.TreeEditor
33330 * @extends Roo.Editor
33331 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33332 * as the editor field.
33334 * @param {TreePanel} tree
33335 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33337 Roo.tree.TreeEditor = function(tree, config){
33338 config = config || {};
33339 var field = config.events ? config : new Roo.form.TextField(config);
33340 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33344 tree.on('beforeclick', this.beforeNodeClick, this);
33345 tree.getTreeEl().on('mousedown', this.hide, this);
33346 this.on('complete', this.updateNode, this);
33347 this.on('beforestartedit', this.fitToTree, this);
33348 this.on('startedit', this.bindScroll, this, {delay:10});
33349 this.on('specialkey', this.onSpecialKey, this);
33352 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33354 * @cfg {String} alignment
33355 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33361 * @cfg {Boolean} hideEl
33362 * True to hide the bound element while the editor is displayed (defaults to false)
33366 * @cfg {String} cls
33367 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33369 cls: "x-small-editor x-tree-editor",
33371 * @cfg {Boolean} shim
33372 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33378 * @cfg {Number} maxWidth
33379 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33380 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33381 * scroll and client offsets into account prior to each edit.
33388 fitToTree : function(ed, el){
33389 var td = this.tree.getTreeEl().dom, nd = el.dom;
33390 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33391 td.scrollLeft = nd.offsetLeft;
33395 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33396 this.setSize(w, '');
33400 triggerEdit : function(node){
33401 this.completeEdit();
33402 this.editNode = node;
33403 this.startEdit(node.ui.textNode, node.text);
33407 bindScroll : function(){
33408 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33412 beforeNodeClick : function(node, e){
33413 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33414 this.lastClick = new Date();
33415 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33417 this.triggerEdit(node);
33423 updateNode : function(ed, value){
33424 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33425 this.editNode.setText(value);
33429 onHide : function(){
33430 Roo.tree.TreeEditor.superclass.onHide.call(this);
33432 this.editNode.ui.focus();
33437 onSpecialKey : function(field, e){
33438 var k = e.getKey();
33442 }else if(k == e.ENTER && !e.hasModifier()){
33444 this.completeEdit();
33447 });//<Script type="text/javascript">
33450 * Ext JS Library 1.1.1
33451 * Copyright(c) 2006-2007, Ext JS, LLC.
33453 * Originally Released Under LGPL - original licence link has changed is not relivant.
33456 * <script type="text/javascript">
33460 * Not documented??? - probably should be...
33463 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33464 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33466 renderElements : function(n, a, targetNode, bulkRender){
33467 //consel.log("renderElements?");
33468 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33470 var t = n.getOwnerTree();
33471 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33473 var cols = t.columns;
33474 var bw = t.borderWidth;
33476 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33477 var cb = typeof a.checked == "boolean";
33478 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33479 var colcls = 'x-t-' + tid + '-c0';
33481 '<li class="x-tree-node">',
33484 '<div class="x-tree-node-el ', a.cls,'">',
33486 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33489 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33490 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33491 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33492 (a.icon ? ' x-tree-node-inline-icon' : ''),
33493 (a.iconCls ? ' '+a.iconCls : ''),
33494 '" unselectable="on" />',
33495 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33496 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33498 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33499 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33500 '<span unselectable="on" qtip="' + tx + '">',
33504 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33505 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33507 for(var i = 1, len = cols.length; i < len; i++){
33509 colcls = 'x-t-' + tid + '-c' +i;
33510 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33511 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33512 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33518 '<div class="x-clear"></div></div>',
33519 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33522 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33523 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33524 n.nextSibling.ui.getEl(), buf.join(""));
33526 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33528 var el = this.wrap.firstChild;
33530 this.elNode = el.firstChild;
33531 this.ranchor = el.childNodes[1];
33532 this.ctNode = this.wrap.childNodes[1];
33533 var cs = el.firstChild.childNodes;
33534 this.indentNode = cs[0];
33535 this.ecNode = cs[1];
33536 this.iconNode = cs[2];
33539 this.checkbox = cs[3];
33542 this.anchor = cs[index];
33544 this.textNode = cs[index].firstChild;
33546 //el.on("click", this.onClick, this);
33547 //el.on("dblclick", this.onDblClick, this);
33550 // console.log(this);
33552 initEvents : function(){
33553 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33556 var a = this.ranchor;
33558 var el = Roo.get(a);
33560 if(Roo.isOpera){ // opera render bug ignores the CSS
33561 el.setStyle("text-decoration", "none");
33564 el.on("click", this.onClick, this);
33565 el.on("dblclick", this.onDblClick, this);
33566 el.on("contextmenu", this.onContextMenu, this);
33570 /*onSelectedChange : function(state){
33573 this.addClass("x-tree-selected");
33576 this.removeClass("x-tree-selected");
33579 addClass : function(cls){
33581 Roo.fly(this.elRow).addClass(cls);
33587 removeClass : function(cls){
33589 Roo.fly(this.elRow).removeClass(cls);
33595 });//<Script type="text/javascript">
33599 * Ext JS Library 1.1.1
33600 * Copyright(c) 2006-2007, Ext JS, LLC.
33602 * Originally Released Under LGPL - original licence link has changed is not relivant.
33605 * <script type="text/javascript">
33610 * @class Roo.tree.ColumnTree
33611 * @extends Roo.data.TreePanel
33612 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33613 * @cfg {int} borderWidth compined right/left border allowance
33615 * @param {String/HTMLElement/Element} el The container element
33616 * @param {Object} config
33618 Roo.tree.ColumnTree = function(el, config)
33620 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33624 * Fire this event on a container when it resizes
33625 * @param {int} w Width
33626 * @param {int} h Height
33630 this.on('resize', this.onResize, this);
33633 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33637 borderWidth: Roo.isBorderBox ? 0 : 2,
33640 render : function(){
33641 // add the header.....
33643 Roo.tree.ColumnTree.superclass.render.apply(this);
33645 this.el.addClass('x-column-tree');
33647 this.headers = this.el.createChild(
33648 {cls:'x-tree-headers'},this.innerCt.dom);
33650 var cols = this.columns, c;
33651 var totalWidth = 0;
33653 var len = cols.length;
33654 for(var i = 0; i < len; i++){
33656 totalWidth += c.width;
33657 this.headEls.push(this.headers.createChild({
33658 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33660 cls:'x-tree-hd-text',
33663 style:'width:'+(c.width-this.borderWidth)+'px;'
33666 this.headers.createChild({cls:'x-clear'});
33667 // prevent floats from wrapping when clipped
33668 this.headers.setWidth(totalWidth);
33669 //this.innerCt.setWidth(totalWidth);
33670 this.innerCt.setStyle({ overflow: 'auto' });
33671 this.onResize(this.width, this.height);
33675 onResize : function(w,h)
33680 this.innerCt.setWidth(this.width);
33681 this.innerCt.setHeight(this.height-20);
33684 var cols = this.columns, c;
33685 var totalWidth = 0;
33687 var len = cols.length;
33688 for(var i = 0; i < len; i++){
33690 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33691 // it's the expander..
33692 expEl = this.headEls[i];
33695 totalWidth += c.width;
33699 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33701 this.headers.setWidth(w-20);
33710 * Ext JS Library 1.1.1
33711 * Copyright(c) 2006-2007, Ext JS, LLC.
33713 * Originally Released Under LGPL - original licence link has changed is not relivant.
33716 * <script type="text/javascript">
33720 * @class Roo.menu.Menu
33721 * @extends Roo.util.Observable
33722 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33723 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33725 * Creates a new Menu
33726 * @param {Object} config Configuration options
33728 Roo.menu.Menu = function(config){
33729 Roo.apply(this, config);
33730 this.id = this.id || Roo.id();
33733 * @event beforeshow
33734 * Fires before this menu is displayed
33735 * @param {Roo.menu.Menu} this
33739 * @event beforehide
33740 * Fires before this menu is hidden
33741 * @param {Roo.menu.Menu} this
33746 * Fires after this menu is displayed
33747 * @param {Roo.menu.Menu} this
33752 * Fires after this menu is hidden
33753 * @param {Roo.menu.Menu} this
33758 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33759 * @param {Roo.menu.Menu} this
33760 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33761 * @param {Roo.EventObject} e
33766 * Fires when the mouse is hovering over this menu
33767 * @param {Roo.menu.Menu} this
33768 * @param {Roo.EventObject} e
33769 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33774 * Fires when the mouse exits this menu
33775 * @param {Roo.menu.Menu} this
33776 * @param {Roo.EventObject} e
33777 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33782 * Fires when a menu item contained in this menu is clicked
33783 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33784 * @param {Roo.EventObject} e
33788 if (this.registerMenu) {
33789 Roo.menu.MenuMgr.register(this);
33792 var mis = this.items;
33793 this.items = new Roo.util.MixedCollection();
33795 this.add.apply(this, mis);
33799 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33801 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33805 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33806 * for bottom-right shadow (defaults to "sides")
33810 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33811 * this menu (defaults to "tl-tr?")
33813 subMenuAlign : "tl-tr?",
33815 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33816 * relative to its element of origin (defaults to "tl-bl?")
33818 defaultAlign : "tl-bl?",
33820 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33822 allowOtherMenus : false,
33824 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33826 registerMenu : true,
33831 render : function(){
33835 var el = this.el = new Roo.Layer({
33837 shadow:this.shadow,
33839 parentEl: this.parentEl || document.body,
33843 this.keyNav = new Roo.menu.MenuNav(this);
33846 el.addClass("x-menu-plain");
33849 el.addClass(this.cls);
33851 // generic focus element
33852 this.focusEl = el.createChild({
33853 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33855 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33856 ul.on("click", this.onClick, this);
33857 ul.on("mouseover", this.onMouseOver, this);
33858 ul.on("mouseout", this.onMouseOut, this);
33859 this.items.each(function(item){
33860 var li = document.createElement("li");
33861 li.className = "x-menu-list-item";
33862 ul.dom.appendChild(li);
33863 item.render(li, this);
33870 autoWidth : function(){
33871 var el = this.el, ul = this.ul;
33875 var w = this.width;
33878 }else if(Roo.isIE){
33879 el.setWidth(this.minWidth);
33880 var t = el.dom.offsetWidth; // force recalc
33881 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33886 delayAutoWidth : function(){
33889 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33891 this.awTask.delay(20);
33896 findTargetItem : function(e){
33897 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33898 if(t && t.menuItemId){
33899 return this.items.get(t.menuItemId);
33904 onClick : function(e){
33906 if(t = this.findTargetItem(e)){
33908 this.fireEvent("click", this, t, e);
33913 setActiveItem : function(item, autoExpand){
33914 if(item != this.activeItem){
33915 if(this.activeItem){
33916 this.activeItem.deactivate();
33918 this.activeItem = item;
33919 item.activate(autoExpand);
33920 }else if(autoExpand){
33926 tryActivate : function(start, step){
33927 var items = this.items;
33928 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33929 var item = items.get(i);
33930 if(!item.disabled && item.canActivate){
33931 this.setActiveItem(item, false);
33939 onMouseOver : function(e){
33941 if(t = this.findTargetItem(e)){
33942 if(t.canActivate && !t.disabled){
33943 this.setActiveItem(t, true);
33946 this.fireEvent("mouseover", this, e, t);
33950 onMouseOut : function(e){
33952 if(t = this.findTargetItem(e)){
33953 if(t == this.activeItem && t.shouldDeactivate(e)){
33954 this.activeItem.deactivate();
33955 delete this.activeItem;
33958 this.fireEvent("mouseout", this, e, t);
33962 * Read-only. Returns true if the menu is currently displayed, else false.
33965 isVisible : function(){
33966 return this.el && !this.hidden;
33970 * Displays this menu relative to another element
33971 * @param {String/HTMLElement/Roo.Element} element The element to align to
33972 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33973 * the element (defaults to this.defaultAlign)
33974 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33976 show : function(el, pos, parentMenu){
33977 this.parentMenu = parentMenu;
33981 this.fireEvent("beforeshow", this);
33982 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33986 * Displays this menu at a specific xy position
33987 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33988 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33990 showAt : function(xy, parentMenu, /* private: */_e){
33991 this.parentMenu = parentMenu;
33996 this.fireEvent("beforeshow", this);
33997 xy = this.el.adjustForConstraints(xy);
34001 this.hidden = false;
34003 this.fireEvent("show", this);
34006 focus : function(){
34008 this.doFocus.defer(50, this);
34012 doFocus : function(){
34014 this.focusEl.focus();
34019 * Hides this menu and optionally all parent menus
34020 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34022 hide : function(deep){
34023 if(this.el && this.isVisible()){
34024 this.fireEvent("beforehide", this);
34025 if(this.activeItem){
34026 this.activeItem.deactivate();
34027 this.activeItem = null;
34030 this.hidden = true;
34031 this.fireEvent("hide", this);
34033 if(deep === true && this.parentMenu){
34034 this.parentMenu.hide(true);
34039 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34040 * Any of the following are valid:
34042 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34043 * <li>An HTMLElement object which will be converted to a menu item</li>
34044 * <li>A menu item config object that will be created as a new menu item</li>
34045 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34046 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34051 var menu = new Roo.menu.Menu();
34053 // Create a menu item to add by reference
34054 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34056 // Add a bunch of items at once using different methods.
34057 // Only the last item added will be returned.
34058 var item = menu.add(
34059 menuItem, // add existing item by ref
34060 'Dynamic Item', // new TextItem
34061 '-', // new separator
34062 { text: 'Config Item' } // new item by config
34065 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34066 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34069 var a = arguments, l = a.length, item;
34070 for(var i = 0; i < l; i++){
34072 if ((typeof(el) == "object") && el.xtype && el.xns) {
34073 el = Roo.factory(el, Roo.menu);
34076 if(el.render){ // some kind of Item
34077 item = this.addItem(el);
34078 }else if(typeof el == "string"){ // string
34079 if(el == "separator" || el == "-"){
34080 item = this.addSeparator();
34082 item = this.addText(el);
34084 }else if(el.tagName || el.el){ // element
34085 item = this.addElement(el);
34086 }else if(typeof el == "object"){ // must be menu item config?
34087 item = this.addMenuItem(el);
34094 * Returns this menu's underlying {@link Roo.Element} object
34095 * @return {Roo.Element} The element
34097 getEl : function(){
34105 * Adds a separator bar to the menu
34106 * @return {Roo.menu.Item} The menu item that was added
34108 addSeparator : function(){
34109 return this.addItem(new Roo.menu.Separator());
34113 * Adds an {@link Roo.Element} object to the menu
34114 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34115 * @return {Roo.menu.Item} The menu item that was added
34117 addElement : function(el){
34118 return this.addItem(new Roo.menu.BaseItem(el));
34122 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34123 * @param {Roo.menu.Item} item The menu item to add
34124 * @return {Roo.menu.Item} The menu item that was added
34126 addItem : function(item){
34127 this.items.add(item);
34129 var li = document.createElement("li");
34130 li.className = "x-menu-list-item";
34131 this.ul.dom.appendChild(li);
34132 item.render(li, this);
34133 this.delayAutoWidth();
34139 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34140 * @param {Object} config A MenuItem config object
34141 * @return {Roo.menu.Item} The menu item that was added
34143 addMenuItem : function(config){
34144 if(!(config instanceof Roo.menu.Item)){
34145 if(typeof config.checked == "boolean"){ // must be check menu item config?
34146 config = new Roo.menu.CheckItem(config);
34148 config = new Roo.menu.Item(config);
34151 return this.addItem(config);
34155 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34156 * @param {String} text The text to display in the menu item
34157 * @return {Roo.menu.Item} The menu item that was added
34159 addText : function(text){
34160 return this.addItem(new Roo.menu.TextItem({ text : text }));
34164 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34165 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34166 * @param {Roo.menu.Item} item The menu item to add
34167 * @return {Roo.menu.Item} The menu item that was added
34169 insert : function(index, item){
34170 this.items.insert(index, item);
34172 var li = document.createElement("li");
34173 li.className = "x-menu-list-item";
34174 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34175 item.render(li, this);
34176 this.delayAutoWidth();
34182 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34183 * @param {Roo.menu.Item} item The menu item to remove
34185 remove : function(item){
34186 this.items.removeKey(item.id);
34191 * Removes and destroys all items in the menu
34193 removeAll : function(){
34195 while(f = this.items.first()){
34201 // MenuNav is a private utility class used internally by the Menu
34202 Roo.menu.MenuNav = function(menu){
34203 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34204 this.scope = this.menu = menu;
34207 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34208 doRelay : function(e, h){
34209 var k = e.getKey();
34210 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34211 this.menu.tryActivate(0, 1);
34214 return h.call(this.scope || this, e, this.menu);
34217 up : function(e, m){
34218 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34219 m.tryActivate(m.items.length-1, -1);
34223 down : function(e, m){
34224 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34225 m.tryActivate(0, 1);
34229 right : function(e, m){
34231 m.activeItem.expandMenu(true);
34235 left : function(e, m){
34237 if(m.parentMenu && m.parentMenu.activeItem){
34238 m.parentMenu.activeItem.activate();
34242 enter : function(e, m){
34244 e.stopPropagation();
34245 m.activeItem.onClick(e);
34246 m.fireEvent("click", this, m.activeItem);
34252 * Ext JS Library 1.1.1
34253 * Copyright(c) 2006-2007, Ext JS, LLC.
34255 * Originally Released Under LGPL - original licence link has changed is not relivant.
34258 * <script type="text/javascript">
34262 * @class Roo.menu.MenuMgr
34263 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34266 Roo.menu.MenuMgr = function(){
34267 var menus, active, groups = {}, attached = false, lastShow = new Date();
34269 // private - called when first menu is created
34272 active = new Roo.util.MixedCollection();
34273 Roo.get(document).addKeyListener(27, function(){
34274 if(active.length > 0){
34281 function hideAll(){
34282 if(active && active.length > 0){
34283 var c = active.clone();
34284 c.each(function(m){
34291 function onHide(m){
34293 if(active.length < 1){
34294 Roo.get(document).un("mousedown", onMouseDown);
34300 function onShow(m){
34301 var last = active.last();
34302 lastShow = new Date();
34305 Roo.get(document).on("mousedown", onMouseDown);
34309 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34310 m.parentMenu.activeChild = m;
34311 }else if(last && last.isVisible()){
34312 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34317 function onBeforeHide(m){
34319 m.activeChild.hide();
34321 if(m.autoHideTimer){
34322 clearTimeout(m.autoHideTimer);
34323 delete m.autoHideTimer;
34328 function onBeforeShow(m){
34329 var pm = m.parentMenu;
34330 if(!pm && !m.allowOtherMenus){
34332 }else if(pm && pm.activeChild && active != m){
34333 pm.activeChild.hide();
34338 function onMouseDown(e){
34339 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34345 function onBeforeCheck(mi, state){
34347 var g = groups[mi.group];
34348 for(var i = 0, l = g.length; i < l; i++){
34350 g[i].setChecked(false);
34359 * Hides all menus that are currently visible
34361 hideAll : function(){
34366 register : function(menu){
34370 menus[menu.id] = menu;
34371 menu.on("beforehide", onBeforeHide);
34372 menu.on("hide", onHide);
34373 menu.on("beforeshow", onBeforeShow);
34374 menu.on("show", onShow);
34375 var g = menu.group;
34376 if(g && menu.events["checkchange"]){
34380 groups[g].push(menu);
34381 menu.on("checkchange", onCheck);
34386 * Returns a {@link Roo.menu.Menu} object
34387 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34388 * be used to generate and return a new Menu instance.
34390 get : function(menu){
34391 if(typeof menu == "string"){ // menu id
34392 return menus[menu];
34393 }else if(menu.events){ // menu instance
34395 }else if(typeof menu.length == 'number'){ // array of menu items?
34396 return new Roo.menu.Menu({items:menu});
34397 }else{ // otherwise, must be a config
34398 return new Roo.menu.Menu(menu);
34403 unregister : function(menu){
34404 delete menus[menu.id];
34405 menu.un("beforehide", onBeforeHide);
34406 menu.un("hide", onHide);
34407 menu.un("beforeshow", onBeforeShow);
34408 menu.un("show", onShow);
34409 var g = menu.group;
34410 if(g && menu.events["checkchange"]){
34411 groups[g].remove(menu);
34412 menu.un("checkchange", onCheck);
34417 registerCheckable : function(menuItem){
34418 var g = menuItem.group;
34423 groups[g].push(menuItem);
34424 menuItem.on("beforecheckchange", onBeforeCheck);
34429 unregisterCheckable : function(menuItem){
34430 var g = menuItem.group;
34432 groups[g].remove(menuItem);
34433 menuItem.un("beforecheckchange", onBeforeCheck);
34439 * Ext JS Library 1.1.1
34440 * Copyright(c) 2006-2007, Ext JS, LLC.
34442 * Originally Released Under LGPL - original licence link has changed is not relivant.
34445 * <script type="text/javascript">
34450 * @class Roo.menu.BaseItem
34451 * @extends Roo.Component
34452 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34453 * management and base configuration options shared by all menu components.
34455 * Creates a new BaseItem
34456 * @param {Object} config Configuration options
34458 Roo.menu.BaseItem = function(config){
34459 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34464 * Fires when this item is clicked
34465 * @param {Roo.menu.BaseItem} this
34466 * @param {Roo.EventObject} e
34471 * Fires when this item is activated
34472 * @param {Roo.menu.BaseItem} this
34476 * @event deactivate
34477 * Fires when this item is deactivated
34478 * @param {Roo.menu.BaseItem} this
34484 this.on("click", this.handler, this.scope, true);
34488 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34490 * @cfg {Function} handler
34491 * A function that will handle the click event of this menu item (defaults to undefined)
34494 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34496 canActivate : false,
34498 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34500 activeClass : "x-menu-item-active",
34502 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34504 hideOnClick : true,
34506 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34511 ctype: "Roo.menu.BaseItem",
34514 actionMode : "container",
34517 render : function(container, parentMenu){
34518 this.parentMenu = parentMenu;
34519 Roo.menu.BaseItem.superclass.render.call(this, container);
34520 this.container.menuItemId = this.id;
34524 onRender : function(container, position){
34525 this.el = Roo.get(this.el);
34526 container.dom.appendChild(this.el.dom);
34530 onClick : function(e){
34531 if(!this.disabled && this.fireEvent("click", this, e) !== false
34532 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34533 this.handleClick(e);
34540 activate : function(){
34544 var li = this.container;
34545 li.addClass(this.activeClass);
34546 this.region = li.getRegion().adjust(2, 2, -2, -2);
34547 this.fireEvent("activate", this);
34552 deactivate : function(){
34553 this.container.removeClass(this.activeClass);
34554 this.fireEvent("deactivate", this);
34558 shouldDeactivate : function(e){
34559 return !this.region || !this.region.contains(e.getPoint());
34563 handleClick : function(e){
34564 if(this.hideOnClick){
34565 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34570 expandMenu : function(autoActivate){
34575 hideMenu : function(){
34580 * Ext JS Library 1.1.1
34581 * Copyright(c) 2006-2007, Ext JS, LLC.
34583 * Originally Released Under LGPL - original licence link has changed is not relivant.
34586 * <script type="text/javascript">
34590 * @class Roo.menu.Adapter
34591 * @extends Roo.menu.BaseItem
34592 * 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.
34593 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34595 * Creates a new Adapter
34596 * @param {Object} config Configuration options
34598 Roo.menu.Adapter = function(component, config){
34599 Roo.menu.Adapter.superclass.constructor.call(this, config);
34600 this.component = component;
34602 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34604 canActivate : true,
34607 onRender : function(container, position){
34608 this.component.render(container);
34609 this.el = this.component.getEl();
34613 activate : function(){
34617 this.component.focus();
34618 this.fireEvent("activate", this);
34623 deactivate : function(){
34624 this.fireEvent("deactivate", this);
34628 disable : function(){
34629 this.component.disable();
34630 Roo.menu.Adapter.superclass.disable.call(this);
34634 enable : function(){
34635 this.component.enable();
34636 Roo.menu.Adapter.superclass.enable.call(this);
34640 * Ext JS Library 1.1.1
34641 * Copyright(c) 2006-2007, Ext JS, LLC.
34643 * Originally Released Under LGPL - original licence link has changed is not relivant.
34646 * <script type="text/javascript">
34650 * @class Roo.menu.TextItem
34651 * @extends Roo.menu.BaseItem
34652 * Adds a static text string to a menu, usually used as either a heading or group separator.
34653 * Note: old style constructor with text is still supported.
34656 * Creates a new TextItem
34657 * @param {Object} cfg Configuration
34659 Roo.menu.TextItem = function(cfg){
34660 if (typeof(cfg) == 'string') {
34663 Roo.apply(this,cfg);
34666 Roo.menu.TextItem.superclass.constructor.call(this);
34669 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34671 * @cfg {Boolean} text Text to show on item.
34676 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34678 hideOnClick : false,
34680 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34682 itemCls : "x-menu-text",
34685 onRender : function(){
34686 var s = document.createElement("span");
34687 s.className = this.itemCls;
34688 s.innerHTML = this.text;
34690 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34694 * Ext JS Library 1.1.1
34695 * Copyright(c) 2006-2007, Ext JS, LLC.
34697 * Originally Released Under LGPL - original licence link has changed is not relivant.
34700 * <script type="text/javascript">
34704 * @class Roo.menu.Separator
34705 * @extends Roo.menu.BaseItem
34706 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34707 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34709 * @param {Object} config Configuration options
34711 Roo.menu.Separator = function(config){
34712 Roo.menu.Separator.superclass.constructor.call(this, config);
34715 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34717 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34719 itemCls : "x-menu-sep",
34721 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34723 hideOnClick : false,
34726 onRender : function(li){
34727 var s = document.createElement("span");
34728 s.className = this.itemCls;
34729 s.innerHTML = " ";
34731 li.addClass("x-menu-sep-li");
34732 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34736 * Ext JS Library 1.1.1
34737 * Copyright(c) 2006-2007, Ext JS, LLC.
34739 * Originally Released Under LGPL - original licence link has changed is not relivant.
34742 * <script type="text/javascript">
34745 * @class Roo.menu.Item
34746 * @extends Roo.menu.BaseItem
34747 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34748 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34749 * activation and click handling.
34751 * Creates a new Item
34752 * @param {Object} config Configuration options
34754 Roo.menu.Item = function(config){
34755 Roo.menu.Item.superclass.constructor.call(this, config);
34757 this.menu = Roo.menu.MenuMgr.get(this.menu);
34760 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34763 * @cfg {String} text
34764 * The text to show on the menu item.
34768 * @cfg {String} HTML to render in menu
34769 * The text to show on the menu item (HTML version).
34773 * @cfg {String} icon
34774 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34778 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34780 itemCls : "x-menu-item",
34782 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34784 canActivate : true,
34786 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34789 // doc'd in BaseItem
34793 ctype: "Roo.menu.Item",
34796 onRender : function(container, position){
34797 var el = document.createElement("a");
34798 el.hideFocus = true;
34799 el.unselectable = "on";
34800 el.href = this.href || "#";
34801 if(this.hrefTarget){
34802 el.target = this.hrefTarget;
34804 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34806 var html = this.html.length ? this.html : String.format('{0}',this.text);
34808 el.innerHTML = String.format(
34809 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34810 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34812 Roo.menu.Item.superclass.onRender.call(this, container, position);
34816 * Sets the text to display in this menu item
34817 * @param {String} text The text to display
34818 * @param {Boolean} isHTML true to indicate text is pure html.
34820 setText : function(text, isHTML){
34828 var html = this.html.length ? this.html : String.format('{0}',this.text);
34830 this.el.update(String.format(
34831 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34832 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34833 this.parentMenu.autoWidth();
34838 handleClick : function(e){
34839 if(!this.href){ // if no link defined, stop the event automatically
34842 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34846 activate : function(autoExpand){
34847 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34857 shouldDeactivate : function(e){
34858 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34859 if(this.menu && this.menu.isVisible()){
34860 return !this.menu.getEl().getRegion().contains(e.getPoint());
34868 deactivate : function(){
34869 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34874 expandMenu : function(autoActivate){
34875 if(!this.disabled && this.menu){
34876 clearTimeout(this.hideTimer);
34877 delete this.hideTimer;
34878 if(!this.menu.isVisible() && !this.showTimer){
34879 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34880 }else if (this.menu.isVisible() && autoActivate){
34881 this.menu.tryActivate(0, 1);
34887 deferExpand : function(autoActivate){
34888 delete this.showTimer;
34889 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34891 this.menu.tryActivate(0, 1);
34896 hideMenu : function(){
34897 clearTimeout(this.showTimer);
34898 delete this.showTimer;
34899 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34900 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34905 deferHide : function(){
34906 delete this.hideTimer;
34911 * Ext JS Library 1.1.1
34912 * Copyright(c) 2006-2007, Ext JS, LLC.
34914 * Originally Released Under LGPL - original licence link has changed is not relivant.
34917 * <script type="text/javascript">
34921 * @class Roo.menu.CheckItem
34922 * @extends Roo.menu.Item
34923 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34925 * Creates a new CheckItem
34926 * @param {Object} config Configuration options
34928 Roo.menu.CheckItem = function(config){
34929 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34932 * @event beforecheckchange
34933 * Fires before the checked value is set, providing an opportunity to cancel if needed
34934 * @param {Roo.menu.CheckItem} this
34935 * @param {Boolean} checked The new checked value that will be set
34937 "beforecheckchange" : true,
34939 * @event checkchange
34940 * Fires after the checked value has been set
34941 * @param {Roo.menu.CheckItem} this
34942 * @param {Boolean} checked The checked value that was set
34944 "checkchange" : true
34946 if(this.checkHandler){
34947 this.on('checkchange', this.checkHandler, this.scope);
34950 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34952 * @cfg {String} group
34953 * All check items with the same group name will automatically be grouped into a single-select
34954 * radio button group (defaults to '')
34957 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34959 itemCls : "x-menu-item x-menu-check-item",
34961 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34963 groupClass : "x-menu-group-item",
34966 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34967 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34968 * initialized with checked = true will be rendered as checked.
34973 ctype: "Roo.menu.CheckItem",
34976 onRender : function(c){
34977 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34979 this.el.addClass(this.groupClass);
34981 Roo.menu.MenuMgr.registerCheckable(this);
34983 this.checked = false;
34984 this.setChecked(true, true);
34989 destroy : function(){
34991 Roo.menu.MenuMgr.unregisterCheckable(this);
34993 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34997 * Set the checked state of this item
34998 * @param {Boolean} checked The new checked value
34999 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35001 setChecked : function(state, suppressEvent){
35002 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35003 if(this.container){
35004 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35006 this.checked = state;
35007 if(suppressEvent !== true){
35008 this.fireEvent("checkchange", this, state);
35014 handleClick : function(e){
35015 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35016 this.setChecked(!this.checked);
35018 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35022 * Ext JS Library 1.1.1
35023 * Copyright(c) 2006-2007, Ext JS, LLC.
35025 * Originally Released Under LGPL - original licence link has changed is not relivant.
35028 * <script type="text/javascript">
35032 * @class Roo.menu.DateItem
35033 * @extends Roo.menu.Adapter
35034 * A menu item that wraps the {@link Roo.DatPicker} component.
35036 * Creates a new DateItem
35037 * @param {Object} config Configuration options
35039 Roo.menu.DateItem = function(config){
35040 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35041 /** The Roo.DatePicker object @type Roo.DatePicker */
35042 this.picker = this.component;
35043 this.addEvents({select: true});
35045 this.picker.on("render", function(picker){
35046 picker.getEl().swallowEvent("click");
35047 picker.container.addClass("x-menu-date-item");
35050 this.picker.on("select", this.onSelect, this);
35053 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35055 onSelect : function(picker, date){
35056 this.fireEvent("select", this, date, picker);
35057 Roo.menu.DateItem.superclass.handleClick.call(this);
35061 * Ext JS Library 1.1.1
35062 * Copyright(c) 2006-2007, Ext JS, LLC.
35064 * Originally Released Under LGPL - original licence link has changed is not relivant.
35067 * <script type="text/javascript">
35071 * @class Roo.menu.ColorItem
35072 * @extends Roo.menu.Adapter
35073 * A menu item that wraps the {@link Roo.ColorPalette} component.
35075 * Creates a new ColorItem
35076 * @param {Object} config Configuration options
35078 Roo.menu.ColorItem = function(config){
35079 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35080 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35081 this.palette = this.component;
35082 this.relayEvents(this.palette, ["select"]);
35083 if(this.selectHandler){
35084 this.on('select', this.selectHandler, this.scope);
35087 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35089 * Ext JS Library 1.1.1
35090 * Copyright(c) 2006-2007, Ext JS, LLC.
35092 * Originally Released Under LGPL - original licence link has changed is not relivant.
35095 * <script type="text/javascript">
35100 * @class Roo.menu.DateMenu
35101 * @extends Roo.menu.Menu
35102 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35104 * Creates a new DateMenu
35105 * @param {Object} config Configuration options
35107 Roo.menu.DateMenu = function(config){
35108 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35110 var di = new Roo.menu.DateItem(config);
35113 * The {@link Roo.DatePicker} instance for this DateMenu
35116 this.picker = di.picker;
35119 * @param {DatePicker} picker
35120 * @param {Date} date
35122 this.relayEvents(di, ["select"]);
35124 this.on('beforeshow', function(){
35126 this.picker.hideMonthPicker(true);
35130 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35134 * Ext JS Library 1.1.1
35135 * Copyright(c) 2006-2007, Ext JS, LLC.
35137 * Originally Released Under LGPL - original licence link has changed is not relivant.
35140 * <script type="text/javascript">
35145 * @class Roo.menu.ColorMenu
35146 * @extends Roo.menu.Menu
35147 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35149 * Creates a new ColorMenu
35150 * @param {Object} config Configuration options
35152 Roo.menu.ColorMenu = function(config){
35153 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35155 var ci = new Roo.menu.ColorItem(config);
35158 * The {@link Roo.ColorPalette} instance for this ColorMenu
35159 * @type ColorPalette
35161 this.palette = ci.palette;
35164 * @param {ColorPalette} palette
35165 * @param {String} color
35167 this.relayEvents(ci, ["select"]);
35169 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35171 * Ext JS Library 1.1.1
35172 * Copyright(c) 2006-2007, Ext JS, LLC.
35174 * Originally Released Under LGPL - original licence link has changed is not relivant.
35177 * <script type="text/javascript">
35181 * @class Roo.form.Field
35182 * @extends Roo.BoxComponent
35183 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35185 * Creates a new Field
35186 * @param {Object} config Configuration options
35188 Roo.form.Field = function(config){
35189 Roo.form.Field.superclass.constructor.call(this, config);
35192 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35194 * @cfg {String} fieldLabel Label to use when rendering a form.
35197 * @cfg {String} qtip Mouse over tip
35201 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35203 invalidClass : "x-form-invalid",
35205 * @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")
35207 invalidText : "The value in this field is invalid",
35209 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35211 focusClass : "x-form-focus",
35213 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35214 automatic validation (defaults to "keyup").
35216 validationEvent : "keyup",
35218 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35220 validateOnBlur : true,
35222 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35224 validationDelay : 250,
35226 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35227 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35229 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35231 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35233 fieldClass : "x-form-field",
35235 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35238 ----------- ----------------------------------------------------------------------
35239 qtip Display a quick tip when the user hovers over the field
35240 title Display a default browser title attribute popup
35241 under Add a block div beneath the field containing the error text
35242 side Add an error icon to the right of the field with a popup on hover
35243 [element id] Add the error text directly to the innerHTML of the specified element
35246 msgTarget : 'qtip',
35248 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35253 * @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.
35258 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35263 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35265 inputType : undefined,
35268 * @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).
35270 tabIndex : undefined,
35273 isFormField : true,
35278 * @property {Roo.Element} fieldEl
35279 * Element Containing the rendered Field (with label etc.)
35282 * @cfg {Mixed} value A value to initialize this field with.
35287 * @cfg {String} name The field's HTML name attribute.
35290 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35294 initComponent : function(){
35295 Roo.form.Field.superclass.initComponent.call(this);
35299 * Fires when this field receives input focus.
35300 * @param {Roo.form.Field} this
35305 * Fires when this field loses input focus.
35306 * @param {Roo.form.Field} this
35310 * @event specialkey
35311 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35312 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35313 * @param {Roo.form.Field} this
35314 * @param {Roo.EventObject} e The event object
35319 * Fires just before the field blurs if the field value has changed.
35320 * @param {Roo.form.Field} this
35321 * @param {Mixed} newValue The new value
35322 * @param {Mixed} oldValue The original value
35327 * Fires after the field has been marked as invalid.
35328 * @param {Roo.form.Field} this
35329 * @param {String} msg The validation message
35334 * Fires after the field has been validated with no errors.
35335 * @param {Roo.form.Field} this
35340 * Fires after the key up
35341 * @param {Roo.form.Field} this
35342 * @param {Roo.EventObject} e The event Object
35349 * Returns the name attribute of the field if available
35350 * @return {String} name The field name
35352 getName: function(){
35353 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35357 onRender : function(ct, position){
35358 Roo.form.Field.superclass.onRender.call(this, ct, position);
35360 var cfg = this.getAutoCreate();
35362 cfg.name = this.name || this.id;
35364 if(this.inputType){
35365 cfg.type = this.inputType;
35367 this.el = ct.createChild(cfg, position);
35369 var type = this.el.dom.type;
35371 if(type == 'password'){
35374 this.el.addClass('x-form-'+type);
35377 this.el.dom.readOnly = true;
35379 if(this.tabIndex !== undefined){
35380 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35383 this.el.addClass([this.fieldClass, this.cls]);
35388 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35389 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35390 * @return {Roo.form.Field} this
35392 applyTo : function(target){
35393 this.allowDomMove = false;
35394 this.el = Roo.get(target);
35395 this.render(this.el.dom.parentNode);
35400 initValue : function(){
35401 if(this.value !== undefined){
35402 this.setValue(this.value);
35403 }else if(this.el.dom.value.length > 0){
35404 this.setValue(this.el.dom.value);
35409 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35411 isDirty : function() {
35412 if(this.disabled) {
35415 return String(this.getValue()) !== String(this.originalValue);
35419 afterRender : function(){
35420 Roo.form.Field.superclass.afterRender.call(this);
35425 fireKey : function(e){
35426 //Roo.log('field ' + e.getKey());
35427 if(e.isNavKeyPress()){
35428 this.fireEvent("specialkey", this, e);
35433 * Resets the current field value to the originally loaded value and clears any validation messages
35435 reset : function(){
35436 this.setValue(this.originalValue);
35437 this.clearInvalid();
35441 initEvents : function(){
35442 // safari killled keypress - so keydown is now used..
35443 this.el.on("keydown" , this.fireKey, this);
35444 this.el.on("focus", this.onFocus, this);
35445 this.el.on("blur", this.onBlur, this);
35446 this.el.relayEvent('keyup', this);
35448 // reference to original value for reset
35449 this.originalValue = this.getValue();
35453 onFocus : function(){
35454 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35455 this.el.addClass(this.focusClass);
35457 if(!this.hasFocus){
35458 this.hasFocus = true;
35459 this.startValue = this.getValue();
35460 this.fireEvent("focus", this);
35464 beforeBlur : Roo.emptyFn,
35467 onBlur : function(){
35469 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35470 this.el.removeClass(this.focusClass);
35472 this.hasFocus = false;
35473 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35476 var v = this.getValue();
35477 if(String(v) !== String(this.startValue)){
35478 this.fireEvent('change', this, v, this.startValue);
35480 this.fireEvent("blur", this);
35484 * Returns whether or not the field value is currently valid
35485 * @param {Boolean} preventMark True to disable marking the field invalid
35486 * @return {Boolean} True if the value is valid, else false
35488 isValid : function(preventMark){
35492 var restore = this.preventMark;
35493 this.preventMark = preventMark === true;
35494 var v = this.validateValue(this.processValue(this.getRawValue()));
35495 this.preventMark = restore;
35500 * Validates the field value
35501 * @return {Boolean} True if the value is valid, else false
35503 validate : function(){
35504 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35505 this.clearInvalid();
35511 processValue : function(value){
35516 // Subclasses should provide the validation implementation by overriding this
35517 validateValue : function(value){
35522 * Mark this field as invalid
35523 * @param {String} msg The validation message
35525 markInvalid : function(msg){
35526 if(!this.rendered || this.preventMark){ // not rendered
35529 this.el.addClass(this.invalidClass);
35530 msg = msg || this.invalidText;
35531 switch(this.msgTarget){
35533 this.el.dom.qtip = msg;
35534 this.el.dom.qclass = 'x-form-invalid-tip';
35535 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35536 Roo.QuickTips.enable();
35540 this.el.dom.title = msg;
35544 var elp = this.el.findParent('.x-form-element', 5, true);
35545 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35546 this.errorEl.setWidth(elp.getWidth(true)-20);
35548 this.errorEl.update(msg);
35549 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35552 if(!this.errorIcon){
35553 var elp = this.el.findParent('.x-form-element', 5, true);
35554 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35556 this.alignErrorIcon();
35557 this.errorIcon.dom.qtip = msg;
35558 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35559 this.errorIcon.show();
35560 this.on('resize', this.alignErrorIcon, this);
35563 var t = Roo.getDom(this.msgTarget);
35565 t.style.display = this.msgDisplay;
35568 this.fireEvent('invalid', this, msg);
35572 alignErrorIcon : function(){
35573 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35577 * Clear any invalid styles/messages for this field
35579 clearInvalid : function(){
35580 if(!this.rendered || this.preventMark){ // not rendered
35583 this.el.removeClass(this.invalidClass);
35584 switch(this.msgTarget){
35586 this.el.dom.qtip = '';
35589 this.el.dom.title = '';
35593 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35597 if(this.errorIcon){
35598 this.errorIcon.dom.qtip = '';
35599 this.errorIcon.hide();
35600 this.un('resize', this.alignErrorIcon, this);
35604 var t = Roo.getDom(this.msgTarget);
35606 t.style.display = 'none';
35609 this.fireEvent('valid', this);
35613 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35614 * @return {Mixed} value The field value
35616 getRawValue : function(){
35617 var v = this.el.getValue();
35618 if(v === this.emptyText){
35625 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35626 * @return {Mixed} value The field value
35628 getValue : function(){
35629 var v = this.el.getValue();
35630 if(v === this.emptyText || v === undefined){
35637 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35638 * @param {Mixed} value The value to set
35640 setRawValue : function(v){
35641 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35645 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35646 * @param {Mixed} value The value to set
35648 setValue : function(v){
35651 this.el.dom.value = (v === null || v === undefined ? '' : v);
35656 adjustSize : function(w, h){
35657 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35658 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35662 adjustWidth : function(tag, w){
35663 tag = tag.toLowerCase();
35664 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35665 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35666 if(tag == 'input'){
35669 if(tag = 'textarea'){
35672 }else if(Roo.isOpera){
35673 if(tag == 'input'){
35676 if(tag = 'textarea'){
35686 // anything other than normal should be considered experimental
35687 Roo.form.Field.msgFx = {
35689 show: function(msgEl, f){
35690 msgEl.setDisplayed('block');
35693 hide : function(msgEl, f){
35694 msgEl.setDisplayed(false).update('');
35699 show: function(msgEl, f){
35700 msgEl.slideIn('t', {stopFx:true});
35703 hide : function(msgEl, f){
35704 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35709 show: function(msgEl, f){
35710 msgEl.fixDisplay();
35711 msgEl.alignTo(f.el, 'tl-tr');
35712 msgEl.slideIn('l', {stopFx:true});
35715 hide : function(msgEl, f){
35716 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35721 * Ext JS Library 1.1.1
35722 * Copyright(c) 2006-2007, Ext JS, LLC.
35724 * Originally Released Under LGPL - original licence link has changed is not relivant.
35727 * <script type="text/javascript">
35732 * @class Roo.form.TextField
35733 * @extends Roo.form.Field
35734 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35735 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35737 * Creates a new TextField
35738 * @param {Object} config Configuration options
35740 Roo.form.TextField = function(config){
35741 Roo.form.TextField.superclass.constructor.call(this, config);
35745 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35746 * according to the default logic, but this event provides a hook for the developer to apply additional
35747 * logic at runtime to resize the field if needed.
35748 * @param {Roo.form.Field} this This text field
35749 * @param {Number} width The new field width
35755 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35757 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35761 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35765 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35769 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35773 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35777 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35779 disableKeyFilter : false,
35781 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35785 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35789 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35791 maxLength : Number.MAX_VALUE,
35793 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35795 minLengthText : "The minimum length for this field is {0}",
35797 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35799 maxLengthText : "The maximum length for this field is {0}",
35801 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35803 selectOnFocus : false,
35805 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35807 blankText : "This field is required",
35809 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35810 * If available, this function will be called only after the basic validators all return true, and will be passed the
35811 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35815 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35816 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35817 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35821 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35825 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35829 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35830 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35832 emptyClass : 'x-form-empty-field',
35835 initEvents : function(){
35836 Roo.form.TextField.superclass.initEvents.call(this);
35837 if(this.validationEvent == 'keyup'){
35838 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35839 this.el.on('keyup', this.filterValidation, this);
35841 else if(this.validationEvent !== false){
35842 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35844 if(this.selectOnFocus || this.emptyText){
35845 this.on("focus", this.preFocus, this);
35846 if(this.emptyText){
35847 this.on('blur', this.postBlur, this);
35848 this.applyEmptyText();
35851 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35852 this.el.on("keypress", this.filterKeys, this);
35855 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35856 this.el.on("click", this.autoSize, this);
35860 processValue : function(value){
35861 if(this.stripCharsRe){
35862 var newValue = value.replace(this.stripCharsRe, '');
35863 if(newValue !== value){
35864 this.setRawValue(newValue);
35871 filterValidation : function(e){
35872 if(!e.isNavKeyPress()){
35873 this.validationTask.delay(this.validationDelay);
35878 onKeyUp : function(e){
35879 if(!e.isNavKeyPress()){
35885 * Resets the current field value to the originally-loaded value and clears any validation messages.
35886 * Also adds emptyText and emptyClass if the original value was blank.
35888 reset : function(){
35889 Roo.form.TextField.superclass.reset.call(this);
35890 this.applyEmptyText();
35893 applyEmptyText : function(){
35894 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35895 this.setRawValue(this.emptyText);
35896 this.el.addClass(this.emptyClass);
35901 preFocus : function(){
35902 if(this.emptyText){
35903 if(this.el.dom.value == this.emptyText){
35904 this.setRawValue('');
35906 this.el.removeClass(this.emptyClass);
35908 if(this.selectOnFocus){
35909 this.el.dom.select();
35914 postBlur : function(){
35915 this.applyEmptyText();
35919 filterKeys : function(e){
35920 var k = e.getKey();
35921 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35924 var c = e.getCharCode(), cc = String.fromCharCode(c);
35925 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35928 if(!this.maskRe.test(cc)){
35933 setValue : function(v){
35934 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35935 this.el.removeClass(this.emptyClass);
35937 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35938 this.applyEmptyText();
35943 * Validates a value according to the field's validation rules and marks the field as invalid
35944 * if the validation fails
35945 * @param {Mixed} value The value to validate
35946 * @return {Boolean} True if the value is valid, else false
35948 validateValue : function(value){
35949 if(value.length < 1 || value === this.emptyText){ // if it's blank
35950 if(this.allowBlank){
35951 this.clearInvalid();
35954 this.markInvalid(this.blankText);
35958 if(value.length < this.minLength){
35959 this.markInvalid(String.format(this.minLengthText, this.minLength));
35962 if(value.length > this.maxLength){
35963 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35967 var vt = Roo.form.VTypes;
35968 if(!vt[this.vtype](value, this)){
35969 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35973 if(typeof this.validator == "function"){
35974 var msg = this.validator(value);
35976 this.markInvalid(msg);
35980 if(this.regex && !this.regex.test(value)){
35981 this.markInvalid(this.regexText);
35988 * Selects text in this field
35989 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35990 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35992 selectText : function(start, end){
35993 var v = this.getRawValue();
35995 start = start === undefined ? 0 : start;
35996 end = end === undefined ? v.length : end;
35997 var d = this.el.dom;
35998 if(d.setSelectionRange){
35999 d.setSelectionRange(start, end);
36000 }else if(d.createTextRange){
36001 var range = d.createTextRange();
36002 range.moveStart("character", start);
36003 range.moveEnd("character", v.length-end);
36010 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36011 * This only takes effect if grow = true, and fires the autosize event.
36013 autoSize : function(){
36014 if(!this.grow || !this.rendered){
36018 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36021 var v = el.dom.value;
36022 var d = document.createElement('div');
36023 d.appendChild(document.createTextNode(v));
36027 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36028 this.el.setWidth(w);
36029 this.fireEvent("autosize", this, w);
36033 * Ext JS Library 1.1.1
36034 * Copyright(c) 2006-2007, Ext JS, LLC.
36036 * Originally Released Under LGPL - original licence link has changed is not relivant.
36039 * <script type="text/javascript">
36043 * @class Roo.form.Hidden
36044 * @extends Roo.form.TextField
36045 * Simple Hidden element used on forms
36047 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36050 * Creates a new Hidden form element.
36051 * @param {Object} config Configuration options
36056 // easy hidden field...
36057 Roo.form.Hidden = function(config){
36058 Roo.form.Hidden.superclass.constructor.call(this, config);
36061 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36063 inputType: 'hidden',
36066 labelSeparator: '',
36068 itemCls : 'x-form-item-display-none'
36076 * Ext JS Library 1.1.1
36077 * Copyright(c) 2006-2007, Ext JS, LLC.
36079 * Originally Released Under LGPL - original licence link has changed is not relivant.
36082 * <script type="text/javascript">
36086 * @class Roo.form.TriggerField
36087 * @extends Roo.form.TextField
36088 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36089 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36090 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36091 * for which you can provide a custom implementation. For example:
36093 var trigger = new Roo.form.TriggerField();
36094 trigger.onTriggerClick = myTriggerFn;
36095 trigger.applyTo('my-field');
36098 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36099 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36100 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36101 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36103 * Create a new TriggerField.
36104 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36105 * to the base TextField)
36107 Roo.form.TriggerField = function(config){
36108 this.mimicing = false;
36109 Roo.form.TriggerField.superclass.constructor.call(this, config);
36112 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36114 * @cfg {String} triggerClass A CSS class to apply to the trigger
36117 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36118 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36120 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36122 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36126 /** @cfg {Boolean} grow @hide */
36127 /** @cfg {Number} growMin @hide */
36128 /** @cfg {Number} growMax @hide */
36134 autoSize: Roo.emptyFn,
36138 deferHeight : true,
36141 actionMode : 'wrap',
36143 onResize : function(w, h){
36144 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36145 if(typeof w == 'number'){
36146 var x = w - this.trigger.getWidth();
36147 this.el.setWidth(this.adjustWidth('input', x));
36148 this.trigger.setStyle('left', x+'px');
36153 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36156 getResizeEl : function(){
36161 getPositionEl : function(){
36166 alignErrorIcon : function(){
36167 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36171 onRender : function(ct, position){
36172 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36173 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36174 this.trigger = this.wrap.createChild(this.triggerConfig ||
36175 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36176 if(this.hideTrigger){
36177 this.trigger.setDisplayed(false);
36179 this.initTrigger();
36181 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36186 initTrigger : function(){
36187 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36188 this.trigger.addClassOnOver('x-form-trigger-over');
36189 this.trigger.addClassOnClick('x-form-trigger-click');
36193 onDestroy : function(){
36195 this.trigger.removeAllListeners();
36196 this.trigger.remove();
36199 this.wrap.remove();
36201 Roo.form.TriggerField.superclass.onDestroy.call(this);
36205 onFocus : function(){
36206 Roo.form.TriggerField.superclass.onFocus.call(this);
36207 if(!this.mimicing){
36208 this.wrap.addClass('x-trigger-wrap-focus');
36209 this.mimicing = true;
36210 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36211 if(this.monitorTab){
36212 this.el.on("keydown", this.checkTab, this);
36218 checkTab : function(e){
36219 if(e.getKey() == e.TAB){
36220 this.triggerBlur();
36225 onBlur : function(){
36230 mimicBlur : function(e, t){
36231 if(!this.wrap.contains(t) && this.validateBlur()){
36232 this.triggerBlur();
36237 triggerBlur : function(){
36238 this.mimicing = false;
36239 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36240 if(this.monitorTab){
36241 this.el.un("keydown", this.checkTab, this);
36243 this.wrap.removeClass('x-trigger-wrap-focus');
36244 Roo.form.TriggerField.superclass.onBlur.call(this);
36248 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36249 validateBlur : function(e, t){
36254 onDisable : function(){
36255 Roo.form.TriggerField.superclass.onDisable.call(this);
36257 this.wrap.addClass('x-item-disabled');
36262 onEnable : function(){
36263 Roo.form.TriggerField.superclass.onEnable.call(this);
36265 this.wrap.removeClass('x-item-disabled');
36270 onShow : function(){
36271 var ae = this.getActionEl();
36274 ae.dom.style.display = '';
36275 ae.dom.style.visibility = 'visible';
36281 onHide : function(){
36282 var ae = this.getActionEl();
36283 ae.dom.style.display = 'none';
36287 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36288 * by an implementing function.
36290 * @param {EventObject} e
36292 onTriggerClick : Roo.emptyFn
36295 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36296 // to be extended by an implementing class. For an example of implementing this class, see the custom
36297 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36298 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36299 initComponent : function(){
36300 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36302 this.triggerConfig = {
36303 tag:'span', cls:'x-form-twin-triggers', cn:[
36304 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36305 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36309 getTrigger : function(index){
36310 return this.triggers[index];
36313 initTrigger : function(){
36314 var ts = this.trigger.select('.x-form-trigger', true);
36315 this.wrap.setStyle('overflow', 'hidden');
36316 var triggerField = this;
36317 ts.each(function(t, all, index){
36318 t.hide = function(){
36319 var w = triggerField.wrap.getWidth();
36320 this.dom.style.display = 'none';
36321 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36323 t.show = function(){
36324 var w = triggerField.wrap.getWidth();
36325 this.dom.style.display = '';
36326 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36328 var triggerIndex = 'Trigger'+(index+1);
36330 if(this['hide'+triggerIndex]){
36331 t.dom.style.display = 'none';
36333 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36334 t.addClassOnOver('x-form-trigger-over');
36335 t.addClassOnClick('x-form-trigger-click');
36337 this.triggers = ts.elements;
36340 onTrigger1Click : Roo.emptyFn,
36341 onTrigger2Click : Roo.emptyFn
36344 * Ext JS Library 1.1.1
36345 * Copyright(c) 2006-2007, Ext JS, LLC.
36347 * Originally Released Under LGPL - original licence link has changed is not relivant.
36350 * <script type="text/javascript">
36354 * @class Roo.form.TextArea
36355 * @extends Roo.form.TextField
36356 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36357 * support for auto-sizing.
36359 * Creates a new TextArea
36360 * @param {Object} config Configuration options
36362 Roo.form.TextArea = function(config){
36363 Roo.form.TextArea.superclass.constructor.call(this, config);
36364 // these are provided exchanges for backwards compat
36365 // minHeight/maxHeight were replaced by growMin/growMax to be
36366 // compatible with TextField growing config values
36367 if(this.minHeight !== undefined){
36368 this.growMin = this.minHeight;
36370 if(this.maxHeight !== undefined){
36371 this.growMax = this.maxHeight;
36375 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36377 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36381 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36385 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36386 * in the field (equivalent to setting overflow: hidden, defaults to false)
36388 preventScrollbars: false,
36390 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36391 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36395 onRender : function(ct, position){
36397 this.defaultAutoCreate = {
36399 style:"width:300px;height:60px;",
36400 autocomplete: "off"
36403 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36405 this.textSizeEl = Roo.DomHelper.append(document.body, {
36406 tag: "pre", cls: "x-form-grow-sizer"
36408 if(this.preventScrollbars){
36409 this.el.setStyle("overflow", "hidden");
36411 this.el.setHeight(this.growMin);
36415 onDestroy : function(){
36416 if(this.textSizeEl){
36417 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36419 Roo.form.TextArea.superclass.onDestroy.call(this);
36423 onKeyUp : function(e){
36424 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36430 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36431 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36433 autoSize : function(){
36434 if(!this.grow || !this.textSizeEl){
36438 var v = el.dom.value;
36439 var ts = this.textSizeEl;
36442 ts.appendChild(document.createTextNode(v));
36445 Roo.fly(ts).setWidth(this.el.getWidth());
36447 v = "  ";
36450 v = v.replace(/\n/g, '<p> </p>');
36452 v += " \n ";
36455 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36456 if(h != this.lastHeight){
36457 this.lastHeight = h;
36458 this.el.setHeight(h);
36459 this.fireEvent("autosize", this, h);
36464 * Ext JS Library 1.1.1
36465 * Copyright(c) 2006-2007, Ext JS, LLC.
36467 * Originally Released Under LGPL - original licence link has changed is not relivant.
36470 * <script type="text/javascript">
36475 * @class Roo.form.NumberField
36476 * @extends Roo.form.TextField
36477 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36479 * Creates a new NumberField
36480 * @param {Object} config Configuration options
36482 Roo.form.NumberField = function(config){
36483 Roo.form.NumberField.superclass.constructor.call(this, config);
36486 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36488 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36490 fieldClass: "x-form-field x-form-num-field",
36492 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36494 allowDecimals : true,
36496 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36498 decimalSeparator : ".",
36500 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36502 decimalPrecision : 2,
36504 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36506 allowNegative : true,
36508 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36510 minValue : Number.NEGATIVE_INFINITY,
36512 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36514 maxValue : Number.MAX_VALUE,
36516 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36518 minText : "The minimum value for this field is {0}",
36520 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36522 maxText : "The maximum value for this field is {0}",
36524 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36525 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36527 nanText : "{0} is not a valid number",
36530 initEvents : function(){
36531 Roo.form.NumberField.superclass.initEvents.call(this);
36532 var allowed = "0123456789";
36533 if(this.allowDecimals){
36534 allowed += this.decimalSeparator;
36536 if(this.allowNegative){
36539 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36540 var keyPress = function(e){
36541 var k = e.getKey();
36542 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36545 var c = e.getCharCode();
36546 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36550 this.el.on("keypress", keyPress, this);
36554 validateValue : function(value){
36555 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36558 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36561 var num = this.parseValue(value);
36563 this.markInvalid(String.format(this.nanText, value));
36566 if(num < this.minValue){
36567 this.markInvalid(String.format(this.minText, this.minValue));
36570 if(num > this.maxValue){
36571 this.markInvalid(String.format(this.maxText, this.maxValue));
36577 getValue : function(){
36578 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36582 parseValue : function(value){
36583 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36584 return isNaN(value) ? '' : value;
36588 fixPrecision : function(value){
36589 var nan = isNaN(value);
36590 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36591 return nan ? '' : value;
36593 return parseFloat(value).toFixed(this.decimalPrecision);
36596 setValue : function(v){
36597 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36601 decimalPrecisionFcn : function(v){
36602 return Math.floor(v);
36605 beforeBlur : function(){
36606 var v = this.parseValue(this.getRawValue());
36608 this.setValue(this.fixPrecision(v));
36613 * Ext JS Library 1.1.1
36614 * Copyright(c) 2006-2007, Ext JS, LLC.
36616 * Originally Released Under LGPL - original licence link has changed is not relivant.
36619 * <script type="text/javascript">
36623 * @class Roo.form.DateField
36624 * @extends Roo.form.TriggerField
36625 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36627 * Create a new DateField
36628 * @param {Object} config
36630 Roo.form.DateField = function(config){
36631 Roo.form.DateField.superclass.constructor.call(this, config);
36637 * Fires when a date is selected
36638 * @param {Roo.form.DateField} combo This combo box
36639 * @param {Date} date The date selected
36646 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36647 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36648 this.ddMatch = null;
36649 if(this.disabledDates){
36650 var dd = this.disabledDates;
36652 for(var i = 0; i < dd.length; i++){
36654 if(i != dd.length-1) re += "|";
36656 this.ddMatch = new RegExp(re + ")");
36660 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36662 * @cfg {String} format
36663 * The default date format string which can be overriden for localization support. The format must be
36664 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36668 * @cfg {String} altFormats
36669 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36670 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36672 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36674 * @cfg {Array} disabledDays
36675 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36677 disabledDays : null,
36679 * @cfg {String} disabledDaysText
36680 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36682 disabledDaysText : "Disabled",
36684 * @cfg {Array} disabledDates
36685 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36686 * expression so they are very powerful. Some examples:
36688 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36689 * <li>["03/08", "09/16"] would disable those days for every year</li>
36690 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36691 * <li>["03/../2006"] would disable every day in March 2006</li>
36692 * <li>["^03"] would disable every day in every March</li>
36694 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36695 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36697 disabledDates : null,
36699 * @cfg {String} disabledDatesText
36700 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36702 disabledDatesText : "Disabled",
36704 * @cfg {Date/String} minValue
36705 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36706 * valid format (defaults to null).
36710 * @cfg {Date/String} maxValue
36711 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36712 * valid format (defaults to null).
36716 * @cfg {String} minText
36717 * The error text to display when the date in the cell is before minValue (defaults to
36718 * 'The date in this field must be after {minValue}').
36720 minText : "The date in this field must be equal to or after {0}",
36722 * @cfg {String} maxText
36723 * The error text to display when the date in the cell is after maxValue (defaults to
36724 * 'The date in this field must be before {maxValue}').
36726 maxText : "The date in this field must be equal to or before {0}",
36728 * @cfg {String} invalidText
36729 * The error text to display when the date in the field is invalid (defaults to
36730 * '{value} is not a valid date - it must be in the format {format}').
36732 invalidText : "{0} is not a valid date - it must be in the format {1}",
36734 * @cfg {String} triggerClass
36735 * An additional CSS class used to style the trigger button. The trigger will always get the
36736 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36737 * which displays a calendar icon).
36739 triggerClass : 'x-form-date-trigger',
36743 * @cfg {bool} useIso
36744 * if enabled, then the date field will use a hidden field to store the
36745 * real value as iso formated date. default (false)
36749 * @cfg {String/Object} autoCreate
36750 * A DomHelper element spec, or true for a default element spec (defaults to
36751 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36754 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36757 hiddenField: false,
36759 onRender : function(ct, position)
36761 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36763 this.el.dom.removeAttribute('name');
36764 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36766 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36767 // prevent input submission
36768 this.hiddenName = this.name;
36775 validateValue : function(value)
36777 value = this.formatDate(value);
36778 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36781 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36784 var svalue = value;
36785 value = this.parseDate(value);
36787 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36790 var time = value.getTime();
36791 if(this.minValue && time < this.minValue.getTime()){
36792 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36795 if(this.maxValue && time > this.maxValue.getTime()){
36796 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36799 if(this.disabledDays){
36800 var day = value.getDay();
36801 for(var i = 0; i < this.disabledDays.length; i++) {
36802 if(day === this.disabledDays[i]){
36803 this.markInvalid(this.disabledDaysText);
36808 var fvalue = this.formatDate(value);
36809 if(this.ddMatch && this.ddMatch.test(fvalue)){
36810 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36817 // Provides logic to override the default TriggerField.validateBlur which just returns true
36818 validateBlur : function(){
36819 return !this.menu || !this.menu.isVisible();
36823 * Returns the current date value of the date field.
36824 * @return {Date} The date value
36826 getValue : function(){
36828 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36832 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36833 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36834 * (the default format used is "m/d/y").
36837 //All of these calls set the same date value (May 4, 2006)
36839 //Pass a date object:
36840 var dt = new Date('5/4/06');
36841 dateField.setValue(dt);
36843 //Pass a date string (default format):
36844 dateField.setValue('5/4/06');
36846 //Pass a date string (custom format):
36847 dateField.format = 'Y-m-d';
36848 dateField.setValue('2006-5-4');
36850 * @param {String/Date} date The date or valid date string
36852 setValue : function(date){
36853 if (this.hiddenField) {
36854 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36856 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36860 parseDate : function(value){
36861 if(!value || value instanceof Date){
36864 var v = Date.parseDate(value, this.format);
36865 if(!v && this.altFormats){
36866 if(!this.altFormatsArray){
36867 this.altFormatsArray = this.altFormats.split("|");
36869 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36870 v = Date.parseDate(value, this.altFormatsArray[i]);
36877 formatDate : function(date, fmt){
36878 return (!date || !(date instanceof Date)) ?
36879 date : date.dateFormat(fmt || this.format);
36884 select: function(m, d){
36886 this.fireEvent('select', this, d);
36888 show : function(){ // retain focus styling
36892 this.focus.defer(10, this);
36893 var ml = this.menuListeners;
36894 this.menu.un("select", ml.select, this);
36895 this.menu.un("show", ml.show, this);
36896 this.menu.un("hide", ml.hide, this);
36901 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36902 onTriggerClick : function(){
36906 if(this.menu == null){
36907 this.menu = new Roo.menu.DateMenu();
36909 Roo.apply(this.menu.picker, {
36910 showClear: this.allowBlank,
36911 minDate : this.minValue,
36912 maxDate : this.maxValue,
36913 disabledDatesRE : this.ddMatch,
36914 disabledDatesText : this.disabledDatesText,
36915 disabledDays : this.disabledDays,
36916 disabledDaysText : this.disabledDaysText,
36917 format : this.format,
36918 minText : String.format(this.minText, this.formatDate(this.minValue)),
36919 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36921 this.menu.on(Roo.apply({}, this.menuListeners, {
36924 this.menu.picker.setValue(this.getValue() || new Date());
36925 this.menu.show(this.el, "tl-bl?");
36928 beforeBlur : function(){
36929 var v = this.parseDate(this.getRawValue());
36935 /** @cfg {Boolean} grow @hide */
36936 /** @cfg {Number} growMin @hide */
36937 /** @cfg {Number} growMax @hide */
36944 * Ext JS Library 1.1.1
36945 * Copyright(c) 2006-2007, Ext JS, LLC.
36947 * Originally Released Under LGPL - original licence link has changed is not relivant.
36950 * <script type="text/javascript">
36955 * @class Roo.form.ComboBox
36956 * @extends Roo.form.TriggerField
36957 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36959 * Create a new ComboBox.
36960 * @param {Object} config Configuration options
36962 Roo.form.ComboBox = function(config){
36963 Roo.form.ComboBox.superclass.constructor.call(this, config);
36967 * Fires when the dropdown list is expanded
36968 * @param {Roo.form.ComboBox} combo This combo box
36973 * Fires when the dropdown list is collapsed
36974 * @param {Roo.form.ComboBox} combo This combo box
36978 * @event beforeselect
36979 * Fires before a list item is selected. Return false to cancel the selection.
36980 * @param {Roo.form.ComboBox} combo This combo box
36981 * @param {Roo.data.Record} record The data record returned from the underlying store
36982 * @param {Number} index The index of the selected item in the dropdown list
36984 'beforeselect' : true,
36987 * Fires when a list item is selected
36988 * @param {Roo.form.ComboBox} combo This combo box
36989 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36990 * @param {Number} index The index of the selected item in the dropdown list
36994 * @event beforequery
36995 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36996 * The event object passed has these properties:
36997 * @param {Roo.form.ComboBox} combo This combo box
36998 * @param {String} query The query
36999 * @param {Boolean} forceAll true to force "all" query
37000 * @param {Boolean} cancel true to cancel the query
37001 * @param {Object} e The query event object
37003 'beforequery': true,
37006 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37007 * @param {Roo.form.ComboBox} combo This combo box
37012 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37013 * @param {Roo.form.ComboBox} combo This combo box
37014 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37020 if(this.transform){
37021 this.allowDomMove = false;
37022 var s = Roo.getDom(this.transform);
37023 if(!this.hiddenName){
37024 this.hiddenName = s.name;
37027 this.mode = 'local';
37028 var d = [], opts = s.options;
37029 for(var i = 0, len = opts.length;i < len; i++){
37031 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37033 this.value = value;
37035 d.push([value, o.text]);
37037 this.store = new Roo.data.SimpleStore({
37039 fields: ['value', 'text'],
37042 this.valueField = 'value';
37043 this.displayField = 'text';
37045 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37046 if(!this.lazyRender){
37047 this.target = true;
37048 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37049 s.parentNode.removeChild(s); // remove it
37050 this.render(this.el.parentNode);
37052 s.parentNode.removeChild(s); // remove it
37057 this.store = Roo.factory(this.store, Roo.data);
37060 this.selectedIndex = -1;
37061 if(this.mode == 'local'){
37062 if(config.queryDelay === undefined){
37063 this.queryDelay = 10;
37065 if(config.minChars === undefined){
37071 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37073 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37076 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37077 * rendering into an Roo.Editor, defaults to false)
37080 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37081 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37084 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37087 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37088 * the dropdown list (defaults to undefined, with no header element)
37092 * @cfg {String/Roo.Template} tpl The template to use to render the output
37096 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37098 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37100 listWidth: undefined,
37102 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37103 * mode = 'remote' or 'text' if mode = 'local')
37105 displayField: undefined,
37107 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37108 * mode = 'remote' or 'value' if mode = 'local').
37109 * Note: use of a valueField requires the user make a selection
37110 * in order for a value to be mapped.
37112 valueField: undefined,
37114 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37115 * field's data value (defaults to the underlying DOM element's name)
37117 hiddenName: undefined,
37119 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37123 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37125 selectedClass: 'x-combo-selected',
37127 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37128 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37129 * which displays a downward arrow icon).
37131 triggerClass : 'x-form-arrow-trigger',
37133 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37137 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37138 * anchor positions (defaults to 'tl-bl')
37140 listAlign: 'tl-bl?',
37142 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37146 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37147 * query specified by the allQuery config option (defaults to 'query')
37149 triggerAction: 'query',
37151 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37152 * (defaults to 4, does not apply if editable = false)
37156 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37157 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37161 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37162 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37166 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37167 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37171 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37172 * when editable = true (defaults to false)
37174 selectOnFocus:false,
37176 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37178 queryParam: 'query',
37180 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37181 * when mode = 'remote' (defaults to 'Loading...')
37183 loadingText: 'Loading...',
37185 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37189 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37193 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37194 * traditional select (defaults to true)
37198 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37202 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37206 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37207 * listWidth has a higher value)
37211 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37212 * allow the user to set arbitrary text into the field (defaults to false)
37214 forceSelection:false,
37216 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37217 * if typeAhead = true (defaults to 250)
37219 typeAheadDelay : 250,
37221 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37222 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37224 valueNotFoundText : undefined,
37226 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37228 blockFocus : false,
37231 * @cfg {Boolean} disableClear Disable showing of clear button.
37233 disableClear : false,
37235 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37237 alwaysQuery : false,
37245 onRender : function(ct, position){
37246 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37247 if(this.hiddenName){
37248 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37250 this.hiddenField.value =
37251 this.hiddenValue !== undefined ? this.hiddenValue :
37252 this.value !== undefined ? this.value : '';
37254 // prevent input submission
37255 this.el.dom.removeAttribute('name');
37258 this.el.dom.setAttribute('autocomplete', 'off');
37261 var cls = 'x-combo-list';
37263 this.list = new Roo.Layer({
37264 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37267 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37268 this.list.setWidth(lw);
37269 this.list.swallowEvent('mousewheel');
37270 this.assetHeight = 0;
37273 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37274 this.assetHeight += this.header.getHeight();
37277 this.innerList = this.list.createChild({cls:cls+'-inner'});
37278 this.innerList.on('mouseover', this.onViewOver, this);
37279 this.innerList.on('mousemove', this.onViewMove, this);
37280 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37282 if(this.allowBlank && !this.pageSize && !this.disableClear){
37283 this.footer = this.list.createChild({cls:cls+'-ft'});
37284 this.pageTb = new Roo.Toolbar(this.footer);
37288 this.footer = this.list.createChild({cls:cls+'-ft'});
37289 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37290 {pageSize: this.pageSize});
37294 if (this.pageTb && this.allowBlank && !this.disableClear) {
37296 this.pageTb.add(new Roo.Toolbar.Fill(), {
37297 cls: 'x-btn-icon x-btn-clear',
37299 handler: function()
37302 _this.clearValue();
37303 _this.onSelect(false, -1);
37308 this.assetHeight += this.footer.getHeight();
37313 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37316 this.view = new Roo.View(this.innerList, this.tpl, {
37317 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37320 this.view.on('click', this.onViewClick, this);
37322 this.store.on('beforeload', this.onBeforeLoad, this);
37323 this.store.on('load', this.onLoad, this);
37324 this.store.on('loadexception', this.collapse, this);
37326 if(this.resizable){
37327 this.resizer = new Roo.Resizable(this.list, {
37328 pinned:true, handles:'se'
37330 this.resizer.on('resize', function(r, w, h){
37331 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37332 this.listWidth = w;
37333 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37334 this.restrictHeight();
37336 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37338 if(!this.editable){
37339 this.editable = true;
37340 this.setEditable(false);
37344 if (typeof(this.events.add.listeners) != 'undefined') {
37346 this.addicon = this.wrap.createChild(
37347 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37349 this.addicon.on('click', function(e) {
37350 this.fireEvent('add', this);
37353 if (typeof(this.events.edit.listeners) != 'undefined') {
37355 this.editicon = this.wrap.createChild(
37356 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37357 if (this.addicon) {
37358 this.editicon.setStyle('margin-left', '40px');
37360 this.editicon.on('click', function(e) {
37362 // we fire even if inothing is selected..
37363 this.fireEvent('edit', this, this.lastData );
37373 initEvents : function(){
37374 Roo.form.ComboBox.superclass.initEvents.call(this);
37376 this.keyNav = new Roo.KeyNav(this.el, {
37377 "up" : function(e){
37378 this.inKeyMode = true;
37382 "down" : function(e){
37383 if(!this.isExpanded()){
37384 this.onTriggerClick();
37386 this.inKeyMode = true;
37391 "enter" : function(e){
37392 this.onViewClick();
37396 "esc" : function(e){
37400 "tab" : function(e){
37401 this.onViewClick(false);
37407 doRelay : function(foo, bar, hname){
37408 if(hname == 'down' || this.scope.isExpanded()){
37409 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37416 this.queryDelay = Math.max(this.queryDelay || 10,
37417 this.mode == 'local' ? 10 : 250);
37418 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37419 if(this.typeAhead){
37420 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37422 if(this.editable !== false){
37423 this.el.on("keyup", this.onKeyUp, this);
37425 if(this.forceSelection){
37426 this.on('blur', this.doForce, this);
37430 onDestroy : function(){
37432 this.view.setStore(null);
37433 this.view.el.removeAllListeners();
37434 this.view.el.remove();
37435 this.view.purgeListeners();
37438 this.list.destroy();
37441 this.store.un('beforeload', this.onBeforeLoad, this);
37442 this.store.un('load', this.onLoad, this);
37443 this.store.un('loadexception', this.collapse, this);
37445 Roo.form.ComboBox.superclass.onDestroy.call(this);
37449 fireKey : function(e){
37450 if(e.isNavKeyPress() && !this.list.isVisible()){
37451 this.fireEvent("specialkey", this, e);
37456 onResize: function(w, h){
37457 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37459 if(typeof w != 'number'){
37460 // we do not handle it!?!?
37463 var tw = this.trigger.getWidth();
37464 tw += this.addicon ? this.addicon.getWidth() : 0;
37465 tw += this.editicon ? this.editicon.getWidth() : 0;
37467 this.el.setWidth( this.adjustWidth('input', x));
37469 this.trigger.setStyle('left', x+'px');
37471 if(this.list && this.listWidth === undefined){
37472 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37473 this.list.setWidth(lw);
37474 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37482 * Allow or prevent the user from directly editing the field text. If false is passed,
37483 * the user will only be able to select from the items defined in the dropdown list. This method
37484 * is the runtime equivalent of setting the 'editable' config option at config time.
37485 * @param {Boolean} value True to allow the user to directly edit the field text
37487 setEditable : function(value){
37488 if(value == this.editable){
37491 this.editable = value;
37493 this.el.dom.setAttribute('readOnly', true);
37494 this.el.on('mousedown', this.onTriggerClick, this);
37495 this.el.addClass('x-combo-noedit');
37497 this.el.dom.setAttribute('readOnly', false);
37498 this.el.un('mousedown', this.onTriggerClick, this);
37499 this.el.removeClass('x-combo-noedit');
37504 onBeforeLoad : function(){
37505 if(!this.hasFocus){
37508 this.innerList.update(this.loadingText ?
37509 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37510 this.restrictHeight();
37511 this.selectedIndex = -1;
37515 onLoad : function(){
37516 if(!this.hasFocus){
37519 if(this.store.getCount() > 0){
37521 this.restrictHeight();
37522 if(this.lastQuery == this.allQuery){
37524 this.el.dom.select();
37526 if(!this.selectByValue(this.value, true)){
37527 this.select(0, true);
37531 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37532 this.taTask.delay(this.typeAheadDelay);
37536 this.onEmptyResults();
37542 onTypeAhead : function(){
37543 if(this.store.getCount() > 0){
37544 var r = this.store.getAt(0);
37545 var newValue = r.data[this.displayField];
37546 var len = newValue.length;
37547 var selStart = this.getRawValue().length;
37548 if(selStart != len){
37549 this.setRawValue(newValue);
37550 this.selectText(selStart, newValue.length);
37556 onSelect : function(record, index){
37557 if(this.fireEvent('beforeselect', this, record, index) !== false){
37558 this.setFromData(index > -1 ? record.data : false);
37560 this.fireEvent('select', this, record, index);
37565 * Returns the currently selected field value or empty string if no value is set.
37566 * @return {String} value The selected value
37568 getValue : function(){
37569 if(this.valueField){
37570 return typeof this.value != 'undefined' ? this.value : '';
37572 return Roo.form.ComboBox.superclass.getValue.call(this);
37577 * Clears any text/value currently set in the field
37579 clearValue : function(){
37580 if(this.hiddenField){
37581 this.hiddenField.value = '';
37584 this.setRawValue('');
37585 this.lastSelectionText = '';
37586 this.applyEmptyText();
37590 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37591 * will be displayed in the field. If the value does not match the data value of an existing item,
37592 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37593 * Otherwise the field will be blank (although the value will still be set).
37594 * @param {String} value The value to match
37596 setValue : function(v){
37598 if(this.valueField){
37599 var r = this.findRecord(this.valueField, v);
37601 text = r.data[this.displayField];
37602 }else if(this.valueNotFoundText !== undefined){
37603 text = this.valueNotFoundText;
37606 this.lastSelectionText = text;
37607 if(this.hiddenField){
37608 this.hiddenField.value = v;
37610 Roo.form.ComboBox.superclass.setValue.call(this, text);
37614 * @property {Object} the last set data for the element
37619 * Sets the value of the field based on a object which is related to the record format for the store.
37620 * @param {Object} value the value to set as. or false on reset?
37622 setFromData : function(o){
37623 var dv = ''; // display value
37624 var vv = ''; // value value..
37626 if (this.displayField) {
37627 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37629 // this is an error condition!!!
37630 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37633 if(this.valueField){
37634 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37636 if(this.hiddenField){
37637 this.hiddenField.value = vv;
37639 this.lastSelectionText = dv;
37640 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37644 // no hidden field.. - we store the value in 'value', but still display
37645 // display field!!!!
37646 this.lastSelectionText = dv;
37647 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37653 reset : function(){
37654 // overridden so that last data is reset..
37655 this.setValue(this.originalValue);
37656 this.clearInvalid();
37657 this.lastData = false;
37660 findRecord : function(prop, value){
37662 if(this.store.getCount() > 0){
37663 this.store.each(function(r){
37664 if(r.data[prop] == value){
37674 onViewMove : function(e, t){
37675 this.inKeyMode = false;
37679 onViewOver : function(e, t){
37680 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37683 var item = this.view.findItemFromChild(t);
37685 var index = this.view.indexOf(item);
37686 this.select(index, false);
37691 onViewClick : function(doFocus){
37692 var index = this.view.getSelectedIndexes()[0];
37693 var r = this.store.getAt(index);
37695 this.onSelect(r, index);
37697 if(doFocus !== false && !this.blockFocus){
37703 restrictHeight : function(){
37704 this.innerList.dom.style.height = '';
37705 var inner = this.innerList.dom;
37706 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37707 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37708 this.list.beginUpdate();
37709 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37710 this.list.alignTo(this.el, this.listAlign);
37711 this.list.endUpdate();
37715 onEmptyResults : function(){
37720 * Returns true if the dropdown list is expanded, else false.
37722 isExpanded : function(){
37723 return this.list.isVisible();
37727 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37728 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37729 * @param {String} value The data value of the item to select
37730 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37731 * selected item if it is not currently in view (defaults to true)
37732 * @return {Boolean} True if the value matched an item in the list, else false
37734 selectByValue : function(v, scrollIntoView){
37735 if(v !== undefined && v !== null){
37736 var r = this.findRecord(this.valueField || this.displayField, v);
37738 this.select(this.store.indexOf(r), scrollIntoView);
37746 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37747 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37748 * @param {Number} index The zero-based index of the list item to select
37749 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37750 * selected item if it is not currently in view (defaults to true)
37752 select : function(index, scrollIntoView){
37753 this.selectedIndex = index;
37754 this.view.select(index);
37755 if(scrollIntoView !== false){
37756 var el = this.view.getNode(index);
37758 this.innerList.scrollChildIntoView(el, false);
37764 selectNext : function(){
37765 var ct = this.store.getCount();
37767 if(this.selectedIndex == -1){
37769 }else if(this.selectedIndex < ct-1){
37770 this.select(this.selectedIndex+1);
37776 selectPrev : function(){
37777 var ct = this.store.getCount();
37779 if(this.selectedIndex == -1){
37781 }else if(this.selectedIndex != 0){
37782 this.select(this.selectedIndex-1);
37788 onKeyUp : function(e){
37789 if(this.editable !== false && !e.isSpecialKey()){
37790 this.lastKey = e.getKey();
37791 this.dqTask.delay(this.queryDelay);
37796 validateBlur : function(){
37797 return !this.list || !this.list.isVisible();
37801 initQuery : function(){
37802 this.doQuery(this.getRawValue());
37806 doForce : function(){
37807 if(this.el.dom.value.length > 0){
37808 this.el.dom.value =
37809 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37810 this.applyEmptyText();
37815 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37816 * query allowing the query action to be canceled if needed.
37817 * @param {String} query The SQL query to execute
37818 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37819 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37820 * saved in the current store (defaults to false)
37822 doQuery : function(q, forceAll){
37823 if(q === undefined || q === null){
37828 forceAll: forceAll,
37832 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37836 forceAll = qe.forceAll;
37837 if(forceAll === true || (q.length >= this.minChars)){
37838 if(this.lastQuery != q || this.alwaysQuery){
37839 this.lastQuery = q;
37840 if(this.mode == 'local'){
37841 this.selectedIndex = -1;
37843 this.store.clearFilter();
37845 this.store.filter(this.displayField, q);
37849 this.store.baseParams[this.queryParam] = q;
37851 params: this.getParams(q)
37856 this.selectedIndex = -1;
37863 getParams : function(q){
37865 //p[this.queryParam] = q;
37868 p.limit = this.pageSize;
37874 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37876 collapse : function(){
37877 if(!this.isExpanded()){
37881 Roo.get(document).un('mousedown', this.collapseIf, this);
37882 Roo.get(document).un('mousewheel', this.collapseIf, this);
37883 if (!this.editable) {
37884 Roo.get(document).un('keydown', this.listKeyPress, this);
37886 this.fireEvent('collapse', this);
37890 collapseIf : function(e){
37891 if(!e.within(this.wrap) && !e.within(this.list)){
37897 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37899 expand : function(){
37900 if(this.isExpanded() || !this.hasFocus){
37903 this.list.alignTo(this.el, this.listAlign);
37905 Roo.get(document).on('mousedown', this.collapseIf, this);
37906 Roo.get(document).on('mousewheel', this.collapseIf, this);
37907 if (!this.editable) {
37908 Roo.get(document).on('keydown', this.listKeyPress, this);
37911 this.fireEvent('expand', this);
37915 // Implements the default empty TriggerField.onTriggerClick function
37916 onTriggerClick : function(){
37920 if(this.isExpanded()){
37922 if (!this.blockFocus) {
37927 this.hasFocus = true;
37928 if(this.triggerAction == 'all') {
37929 this.doQuery(this.allQuery, true);
37931 this.doQuery(this.getRawValue());
37933 if (!this.blockFocus) {
37938 listKeyPress : function(e)
37940 //Roo.log('listkeypress');
37941 // scroll to first matching element based on key pres..
37942 if (e.isSpecialKey()) {
37945 var k = String.fromCharCode(e.getKey()).toUpperCase();
37948 var csel = this.view.getSelectedNodes();
37949 var cselitem = false;
37951 var ix = this.view.indexOf(csel[0]);
37952 cselitem = this.store.getAt(ix);
37953 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
37959 this.store.each(function(v) {
37961 // start at existing selection.
37962 if (cselitem.id == v.id) {
37968 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
37969 match = this.store.indexOf(v);
37974 if (match === false) {
37975 return true; // no more action?
37978 this.view.select(match);
37979 var sn = Roo.get(this.view.getSelectedNodes()[0])
37980 sn.scrollIntoView(sn.dom.parentNode, false);
37984 * @cfg {Boolean} grow
37988 * @cfg {Number} growMin
37992 * @cfg {Number} growMax
38001 * Ext JS Library 1.1.1
38002 * Copyright(c) 2006-2007, Ext JS, LLC.
38004 * Originally Released Under LGPL - original licence link has changed is not relivant.
38007 * <script type="text/javascript">
38010 * @class Roo.form.Checkbox
38011 * @extends Roo.form.Field
38012 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38014 * Creates a new Checkbox
38015 * @param {Object} config Configuration options
38017 Roo.form.Checkbox = function(config){
38018 Roo.form.Checkbox.superclass.constructor.call(this, config);
38022 * Fires when the checkbox is checked or unchecked.
38023 * @param {Roo.form.Checkbox} this This checkbox
38024 * @param {Boolean} checked The new checked value
38030 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38032 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38034 focusClass : undefined,
38036 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38038 fieldClass: "x-form-field",
38040 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38044 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38045 * {tag: "input", type: "checkbox", autocomplete: "off"})
38047 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38049 * @cfg {String} boxLabel The text that appears beside the checkbox
38053 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38057 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38059 valueOff: '0', // value when not checked..
38061 actionMode : 'viewEl',
38064 itemCls : 'x-menu-check-item x-form-item',
38065 groupClass : 'x-menu-group-item',
38066 inputType : 'hidden',
38069 inSetChecked: false, // check that we are not calling self...
38071 inputElement: false, // real input element?
38072 basedOn: false, // ????
38074 isFormField: true, // not sure where this is needed!!!!
38076 onResize : function(){
38077 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38078 if(!this.boxLabel){
38079 this.el.alignTo(this.wrap, 'c-c');
38083 initEvents : function(){
38084 Roo.form.Checkbox.superclass.initEvents.call(this);
38085 this.el.on("click", this.onClick, this);
38086 this.el.on("change", this.onClick, this);
38090 getResizeEl : function(){
38094 getPositionEl : function(){
38099 onRender : function(ct, position){
38100 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38102 if(this.inputValue !== undefined){
38103 this.el.dom.value = this.inputValue;
38106 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38107 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38108 var viewEl = this.wrap.createChild({
38109 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38110 this.viewEl = viewEl;
38111 this.wrap.on('click', this.onClick, this);
38113 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38114 this.el.on('propertychange', this.setFromHidden, this); //ie
38119 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38120 // viewEl.on('click', this.onClick, this);
38122 //if(this.checked){
38123 this.setChecked(this.checked);
38125 //this.checked = this.el.dom;
38131 initValue : Roo.emptyFn,
38134 * Returns the checked state of the checkbox.
38135 * @return {Boolean} True if checked, else false
38137 getValue : function(){
38139 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38141 return this.valueOff;
38146 onClick : function(){
38147 this.setChecked(!this.checked);
38149 //if(this.el.dom.checked != this.checked){
38150 // this.setValue(this.el.dom.checked);
38155 * Sets the checked state of the checkbox.
38156 * On is always based on a string comparison between inputValue and the param.
38157 * @param {Boolean/String} value - the value to set
38158 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38160 setValue : function(v,suppressEvent){
38163 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38164 //if(this.el && this.el.dom){
38165 // this.el.dom.checked = this.checked;
38166 // this.el.dom.defaultChecked = this.checked;
38168 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38169 //this.fireEvent("check", this, this.checked);
38172 setChecked : function(state,suppressEvent)
38174 if (this.inSetChecked) {
38175 this.checked = state;
38181 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38183 this.checked = state;
38184 if(suppressEvent !== true){
38185 this.fireEvent('check', this, state);
38187 this.inSetChecked = true;
38188 this.el.dom.value = state ? this.inputValue : this.valueOff;
38189 this.inSetChecked = false;
38192 // handle setting of hidden value by some other method!!?!?
38193 setFromHidden: function()
38198 //console.log("SET FROM HIDDEN");
38199 //alert('setFrom hidden');
38200 this.setValue(this.el.dom.value);
38203 onDestroy : function()
38206 Roo.get(this.viewEl).remove();
38209 Roo.form.Checkbox.superclass.onDestroy.call(this);
38214 * Ext JS Library 1.1.1
38215 * Copyright(c) 2006-2007, Ext JS, LLC.
38217 * Originally Released Under LGPL - original licence link has changed is not relivant.
38220 * <script type="text/javascript">
38224 * @class Roo.form.Radio
38225 * @extends Roo.form.Checkbox
38226 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38227 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38229 * Creates a new Radio
38230 * @param {Object} config Configuration options
38232 Roo.form.Radio = function(){
38233 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38235 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38236 inputType: 'radio',
38239 * If this radio is part of a group, it will return the selected value
38242 getGroupValue : function(){
38243 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38245 });//<script type="text/javascript">
38248 * Ext JS Library 1.1.1
38249 * Copyright(c) 2006-2007, Ext JS, LLC.
38250 * licensing@extjs.com
38252 * http://www.extjs.com/license
38258 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38259 * - IE ? - no idea how much works there.
38267 * @class Ext.form.HtmlEditor
38268 * @extends Ext.form.Field
38269 * Provides a lightweight HTML Editor component.
38270 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38272 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38273 * supported by this editor.</b><br/><br/>
38274 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38275 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38277 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38279 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38283 * @cfg {String} createLinkText The default text for the create link prompt
38285 createLinkText : 'Please enter the URL for the link:',
38287 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38289 defaultLinkValue : 'http:/'+'/',
38295 // private properties
38296 validationEvent : false,
38298 initialized : false,
38300 sourceEditMode : false,
38301 onFocus : Roo.emptyFn,
38303 hideMode:'offsets',
38304 defaultAutoCreate : {
38306 style:"width:500px;height:300px;",
38307 autocomplete: "off"
38311 initComponent : function(){
38314 * @event initialize
38315 * Fires when the editor is fully initialized (including the iframe)
38316 * @param {HtmlEditor} this
38321 * Fires when the editor is first receives the focus. Any insertion must wait
38322 * until after this event.
38323 * @param {HtmlEditor} this
38327 * @event beforesync
38328 * Fires before the textarea is updated with content from the editor iframe. Return false
38329 * to cancel the sync.
38330 * @param {HtmlEditor} this
38331 * @param {String} html
38335 * @event beforepush
38336 * Fires before the iframe editor is updated with content from the textarea. Return false
38337 * to cancel the push.
38338 * @param {HtmlEditor} this
38339 * @param {String} html
38344 * Fires when the textarea is updated with content from the editor iframe.
38345 * @param {HtmlEditor} this
38346 * @param {String} html
38351 * Fires when the iframe editor is updated with content from the textarea.
38352 * @param {HtmlEditor} this
38353 * @param {String} html
38357 * @event editmodechange
38358 * Fires when the editor switches edit modes
38359 * @param {HtmlEditor} this
38360 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38362 editmodechange: true,
38364 * @event editorevent
38365 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38366 * @param {HtmlEditor} this
38373 * Protected method that will not generally be called directly. It
38374 * is called when the editor creates its toolbar. Override this method if you need to
38375 * add custom toolbar buttons.
38376 * @param {HtmlEditor} editor
38378 createToolbar : function(editor){
38379 if (!editor.toolbars || !editor.toolbars.length) {
38380 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38383 for (var i =0 ; i < editor.toolbars.length;i++) {
38384 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38385 editor.toolbars[i].init(editor);
38392 * Protected method that will not generally be called directly. It
38393 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38394 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38396 getDocMarkup : function(){
38397 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38401 onRender : function(ct, position){
38402 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38403 this.el.dom.style.border = '0 none';
38404 this.el.dom.setAttribute('tabIndex', -1);
38405 this.el.addClass('x-hidden');
38406 if(Roo.isIE){ // fix IE 1px bogus margin
38407 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38409 this.wrap = this.el.wrap({
38410 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38413 this.frameId = Roo.id();
38414 this.createToolbar(this);
38421 var iframe = this.wrap.createChild({
38424 name: this.frameId,
38425 frameBorder : 'no',
38426 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38429 // console.log(iframe);
38430 //this.wrap.dom.appendChild(iframe);
38432 this.iframe = iframe.dom;
38434 this.assignDocWin();
38436 this.doc.designMode = 'on';
38439 this.doc.write(this.getDocMarkup());
38443 var task = { // must defer to wait for browser to be ready
38445 //console.log("run task?" + this.doc.readyState);
38446 this.assignDocWin();
38447 if(this.doc.body || this.doc.readyState == 'complete'){
38449 this.doc.designMode="on";
38453 Roo.TaskMgr.stop(task);
38454 this.initEditor.defer(10, this);
38461 Roo.TaskMgr.start(task);
38464 this.setSize(this.el.getSize());
38469 onResize : function(w, h){
38470 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38471 if(this.el && this.iframe){
38472 if(typeof w == 'number'){
38473 var aw = w - this.wrap.getFrameWidth('lr');
38474 this.el.setWidth(this.adjustWidth('textarea', aw));
38475 this.iframe.style.width = aw + 'px';
38477 if(typeof h == 'number'){
38479 for (var i =0; i < this.toolbars.length;i++) {
38480 // fixme - ask toolbars for heights?
38481 tbh += this.toolbars[i].tb.el.getHeight();
38487 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38488 this.el.setHeight(this.adjustWidth('textarea', ah));
38489 this.iframe.style.height = ah + 'px';
38491 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38498 * Toggles the editor between standard and source edit mode.
38499 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38501 toggleSourceEdit : function(sourceEditMode){
38503 this.sourceEditMode = sourceEditMode === true;
38505 if(this.sourceEditMode){
38508 this.iframe.className = 'x-hidden';
38509 this.el.removeClass('x-hidden');
38510 this.el.dom.removeAttribute('tabIndex');
38515 this.iframe.className = '';
38516 this.el.addClass('x-hidden');
38517 this.el.dom.setAttribute('tabIndex', -1);
38520 this.setSize(this.wrap.getSize());
38521 this.fireEvent('editmodechange', this, this.sourceEditMode);
38524 // private used internally
38525 createLink : function(){
38526 var url = prompt(this.createLinkText, this.defaultLinkValue);
38527 if(url && url != 'http:/'+'/'){
38528 this.relayCmd('createlink', url);
38532 // private (for BoxComponent)
38533 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38535 // private (for BoxComponent)
38536 getResizeEl : function(){
38540 // private (for BoxComponent)
38541 getPositionEl : function(){
38546 initEvents : function(){
38547 this.originalValue = this.getValue();
38551 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38554 markInvalid : Roo.emptyFn,
38556 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38559 clearInvalid : Roo.emptyFn,
38561 setValue : function(v){
38562 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38567 * Protected method that will not generally be called directly. If you need/want
38568 * custom HTML cleanup, this is the method you should override.
38569 * @param {String} html The HTML to be cleaned
38570 * return {String} The cleaned HTML
38572 cleanHtml : function(html){
38573 html = String(html);
38574 if(html.length > 5){
38575 if(Roo.isSafari){ // strip safari nonsense
38576 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38579 if(html == ' '){
38586 * Protected method that will not generally be called directly. Syncs the contents
38587 * of the editor iframe with the textarea.
38589 syncValue : function(){
38590 if(this.initialized){
38591 var bd = (this.doc.body || this.doc.documentElement);
38592 var html = bd.innerHTML;
38594 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38595 var m = bs.match(/text-align:(.*?);/i);
38597 html = '<div style="'+m[0]+'">' + html + '</div>';
38600 html = this.cleanHtml(html);
38601 if(this.fireEvent('beforesync', this, html) !== false){
38602 this.el.dom.value = html;
38603 this.fireEvent('sync', this, html);
38609 * Protected method that will not generally be called directly. Pushes the value of the textarea
38610 * into the iframe editor.
38612 pushValue : function(){
38613 if(this.initialized){
38614 var v = this.el.dom.value;
38618 if(this.fireEvent('beforepush', this, v) !== false){
38619 (this.doc.body || this.doc.documentElement).innerHTML = v;
38620 this.fireEvent('push', this, v);
38626 deferFocus : function(){
38627 this.focus.defer(10, this);
38631 focus : function(){
38632 if(this.win && !this.sourceEditMode){
38639 assignDocWin: function()
38641 var iframe = this.iframe;
38644 this.doc = iframe.contentWindow.document;
38645 this.win = iframe.contentWindow;
38647 if (!Roo.get(this.frameId)) {
38650 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38651 this.win = Roo.get(this.frameId).dom.contentWindow;
38656 initEditor : function(){
38657 //console.log("INIT EDITOR");
38658 this.assignDocWin();
38662 this.doc.designMode="on";
38664 this.doc.write(this.getDocMarkup());
38667 var dbody = (this.doc.body || this.doc.documentElement);
38668 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38669 // this copies styles from the containing element into thsi one..
38670 // not sure why we need all of this..
38671 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38672 ss['background-attachment'] = 'fixed'; // w3c
38673 dbody.bgProperties = 'fixed'; // ie
38674 Roo.DomHelper.applyStyles(dbody, ss);
38675 Roo.EventManager.on(this.doc, {
38676 'mousedown': this.onEditorEvent,
38677 'dblclick': this.onEditorEvent,
38678 'click': this.onEditorEvent,
38679 'keyup': this.onEditorEvent,
38684 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38686 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38687 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38689 this.initialized = true;
38691 this.fireEvent('initialize', this);
38696 onDestroy : function(){
38702 for (var i =0; i < this.toolbars.length;i++) {
38703 // fixme - ask toolbars for heights?
38704 this.toolbars[i].onDestroy();
38707 this.wrap.dom.innerHTML = '';
38708 this.wrap.remove();
38713 onFirstFocus : function(){
38715 this.assignDocWin();
38718 this.activated = true;
38719 for (var i =0; i < this.toolbars.length;i++) {
38720 this.toolbars[i].onFirstFocus();
38723 if(Roo.isGecko){ // prevent silly gecko errors
38725 var s = this.win.getSelection();
38726 if(!s.focusNode || s.focusNode.nodeType != 3){
38727 var r = s.getRangeAt(0);
38728 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38733 this.execCmd('useCSS', true);
38734 this.execCmd('styleWithCSS', false);
38737 this.fireEvent('activate', this);
38741 adjustFont: function(btn){
38742 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38743 //if(Roo.isSafari){ // safari
38746 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38747 if(Roo.isSafari){ // safari
38748 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38749 v = (v < 10) ? 10 : v;
38750 v = (v > 48) ? 48 : v;
38751 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38756 v = Math.max(1, v+adjust);
38758 this.execCmd('FontSize', v );
38761 onEditorEvent : function(e){
38762 this.fireEvent('editorevent', this, e);
38763 // this.updateToolbar();
38767 insertTag : function(tg)
38769 // could be a bit smarter... -> wrap the current selected tRoo..
38771 this.execCmd("formatblock", tg);
38775 insertText : function(txt)
38779 range = this.createRange();
38780 range.deleteContents();
38781 //alert(Sender.getAttribute('label'));
38783 range.insertNode(this.doc.createTextNode(txt));
38787 relayBtnCmd : function(btn){
38788 this.relayCmd(btn.cmd);
38792 * Executes a Midas editor command on the editor document and performs necessary focus and
38793 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38794 * @param {String} cmd The Midas command
38795 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38797 relayCmd : function(cmd, value){
38799 this.execCmd(cmd, value);
38800 this.fireEvent('editorevent', this);
38801 //this.updateToolbar();
38806 * Executes a Midas editor command directly on the editor document.
38807 * For visual commands, you should use {@link #relayCmd} instead.
38808 * <b>This should only be called after the editor is initialized.</b>
38809 * @param {String} cmd The Midas command
38810 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38812 execCmd : function(cmd, value){
38813 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38819 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38821 * @param {String} text
38823 insertAtCursor : function(text){
38824 if(!this.activated){
38829 var r = this.doc.selection.createRange();
38836 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38838 this.execCmd('InsertHTML', text);
38843 mozKeyPress : function(e){
38845 var c = e.getCharCode(), cmd;
38848 c = String.fromCharCode(c).toLowerCase();
38859 this.cleanUpPaste.defer(100, this);
38867 e.preventDefault();
38875 fixKeys : function(){ // load time branching for fastest keydown performance
38877 return function(e){
38878 var k = e.getKey(), r;
38881 r = this.doc.selection.createRange();
38884 r.pasteHTML('    ');
38891 r = this.doc.selection.createRange();
38893 var target = r.parentElement();
38894 if(!target || target.tagName.toLowerCase() != 'li'){
38896 r.pasteHTML('<br />');
38902 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38903 this.cleanUpPaste.defer(100, this);
38909 }else if(Roo.isOpera){
38910 return function(e){
38911 var k = e.getKey();
38915 this.execCmd('InsertHTML','    ');
38918 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38919 this.cleanUpPaste.defer(100, this);
38924 }else if(Roo.isSafari){
38925 return function(e){
38926 var k = e.getKey();
38930 this.execCmd('InsertText','\t');
38934 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38935 this.cleanUpPaste.defer(100, this);
38943 getAllAncestors: function()
38945 var p = this.getSelectedNode();
38948 a.push(p); // push blank onto stack..
38949 p = this.getParentElement();
38953 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38957 a.push(this.doc.body);
38961 lastSelNode : false,
38964 getSelection : function()
38966 this.assignDocWin();
38967 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38970 getSelectedNode: function()
38972 // this may only work on Gecko!!!
38974 // should we cache this!!!!
38979 var range = this.createRange(this.getSelection());
38982 var parent = range.parentElement();
38984 var testRange = range.duplicate();
38985 testRange.moveToElementText(parent);
38986 if (testRange.inRange(range)) {
38989 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38992 parent = parent.parentElement;
38998 var ar = range.endContainer.childNodes;
39000 ar = range.commonAncestorContainer.childNodes;
39001 //alert(ar.length);
39004 var other_nodes = [];
39005 var has_other_nodes = false;
39006 for (var i=0;i<ar.length;i++) {
39007 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39010 // fullly contained node.
39012 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39017 // probably selected..
39018 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39019 other_nodes.push(ar[i]);
39022 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39027 has_other_nodes = true;
39029 if (!nodes.length && other_nodes.length) {
39030 nodes= other_nodes;
39032 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39038 createRange: function(sel)
39040 // this has strange effects when using with
39041 // top toolbar - not sure if it's a great idea.
39042 //this.editor.contentWindow.focus();
39043 if (typeof sel != "undefined") {
39045 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39047 return this.doc.createRange();
39050 return this.doc.createRange();
39053 getParentElement: function()
39056 this.assignDocWin();
39057 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39059 var range = this.createRange(sel);
39062 var p = range.commonAncestorContainer;
39063 while (p.nodeType == 3) { // text node
39075 // BC Hacks - cause I cant work out what i was trying to do..
39076 rangeIntersectsNode : function(range, node)
39078 var nodeRange = node.ownerDocument.createRange();
39080 nodeRange.selectNode(node);
39083 nodeRange.selectNodeContents(node);
39086 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39087 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39089 rangeCompareNode : function(range, node) {
39090 var nodeRange = node.ownerDocument.createRange();
39092 nodeRange.selectNode(node);
39094 nodeRange.selectNodeContents(node);
39096 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39097 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39099 if (nodeIsBefore && !nodeIsAfter)
39101 if (!nodeIsBefore && nodeIsAfter)
39103 if (nodeIsBefore && nodeIsAfter)
39109 // private? - in a new class?
39110 cleanUpPaste : function()
39112 // cleans up the whole document..
39113 // console.log('cleanuppaste');
39114 this.cleanUpChildren(this.doc.body)
39118 cleanUpChildren : function (n)
39120 if (!n.childNodes.length) {
39123 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39124 this.cleanUpChild(n.childNodes[i]);
39131 cleanUpChild : function (node)
39133 //console.log(node);
39134 if (node.nodeName == "#text") {
39135 // clean up silly Windows -- stuff?
39138 if (node.nodeName == "#comment") {
39139 node.parentNode.removeChild(node);
39140 // clean up silly Windows -- stuff?
39144 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39146 node.parentNode.removeChild(node);
39150 if (!node.attributes || !node.attributes.length) {
39151 this.cleanUpChildren(node);
39155 function cleanAttr(n,v)
39158 if (v.match(/^\./) || v.match(/^\//)) {
39161 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39164 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39165 node.removeAttribute(n);
39169 function cleanStyle(n,v)
39171 if (v.match(/expression/)) { //XSS?? should we even bother..
39172 node.removeAttribute(n);
39177 var parts = v.split(/;/);
39178 Roo.each(parts, function(p) {
39179 p = p.replace(/\s+/g,'');
39183 var l = p.split(':').shift().replace(/\s+/g,'');
39185 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39186 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39187 node.removeAttribute(n);
39196 for (var i = node.attributes.length-1; i > -1 ; i--) {
39197 var a = node.attributes[i];
39199 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39200 node.removeAttribute(a.name);
39203 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39204 cleanAttr(a.name,a.value); // fixme..
39207 if (a.name == 'style') {
39208 cleanStyle(a.name,a.value);
39210 /// clean up MS crap..
39211 if (a.name == 'class') {
39212 if (a.value.match(/^Mso/)) {
39213 node.className = '';
39223 this.cleanUpChildren(node);
39229 // hide stuff that is not compatible
39243 * @event specialkey
39247 * @cfg {String} fieldClass @hide
39250 * @cfg {String} focusClass @hide
39253 * @cfg {String} autoCreate @hide
39256 * @cfg {String} inputType @hide
39259 * @cfg {String} invalidClass @hide
39262 * @cfg {String} invalidText @hide
39265 * @cfg {String} msgFx @hide
39268 * @cfg {String} validateOnBlur @hide
39272 Roo.form.HtmlEditor.white = [
39273 'area', 'br', 'img', 'input', 'hr', 'wbr',
39275 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39276 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39277 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39278 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39279 'table', 'ul', 'xmp',
39281 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39284 'dir', 'menu', 'ol', 'ul', 'dl',
39290 Roo.form.HtmlEditor.black = [
39291 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39293 'base', 'basefont', 'bgsound', 'blink', 'body',
39294 'frame', 'frameset', 'head', 'html', 'ilayer',
39295 'iframe', 'layer', 'link', 'meta', 'object',
39296 'script', 'style' ,'title', 'xml' // clean later..
39298 Roo.form.HtmlEditor.clean = [
39299 'script', 'style', 'title', 'xml'
39304 Roo.form.HtmlEditor.ablack = [
39308 Roo.form.HtmlEditor.aclean = [
39309 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39313 Roo.form.HtmlEditor.pwhite= [
39314 'http', 'https', 'mailto'
39317 Roo.form.HtmlEditor.cwhite= [
39322 // <script type="text/javascript">
39325 * Ext JS Library 1.1.1
39326 * Copyright(c) 2006-2007, Ext JS, LLC.
39332 * @class Roo.form.HtmlEditorToolbar1
39337 new Roo.form.HtmlEditor({
39340 new Roo.form.HtmlEditorToolbar1({
39341 disable : { fonts: 1 , format: 1, ..., ... , ...],
39347 * @cfg {Object} disable List of elements to disable..
39348 * @cfg {Array} btns List of additional buttons.
39352 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39355 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39358 Roo.apply(this, config);
39359 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39360 // dont call parent... till later.
39363 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39371 * @cfg {Object} disable List of toolbar elements to disable
39376 * @cfg {Array} fontFamilies An array of available font families
39394 // "á" , ?? a acute?
39399 "°" // , // degrees
39401 // "é" , // e ecute
39402 // "ú" , // u ecute?
39405 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39406 "input:submit", "input:button", "select", "textarea", "label" ],
39409 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39411 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39414 * @cfg {String} defaultFont default font to use.
39416 defaultFont: 'tahoma',
39418 fontSelect : false,
39421 formatCombo : false,
39423 init : function(editor)
39425 this.editor = editor;
39428 var fid = editor.frameId;
39430 function btn(id, toggle, handler){
39431 var xid = fid + '-'+ id ;
39435 cls : 'x-btn-icon x-edit-'+id,
39436 enableToggle:toggle !== false,
39437 scope: editor, // was editor...
39438 handler:handler||editor.relayBtnCmd,
39439 clickEvent:'mousedown',
39440 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39447 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39449 // stop form submits
39450 tb.el.on('click', function(e){
39451 e.preventDefault(); // what does this do?
39454 if(!this.disable.font && !Roo.isSafari){
39455 /* why no safari for fonts
39456 editor.fontSelect = tb.el.createChild({
39459 cls:'x-font-select',
39460 html: editor.createFontOptions()
39462 editor.fontSelect.on('change', function(){
39463 var font = editor.fontSelect.dom.value;
39464 editor.relayCmd('fontname', font);
39465 editor.deferFocus();
39468 editor.fontSelect.dom,
39473 if(!this.disable.formats){
39474 this.formatCombo = new Roo.form.ComboBox({
39475 store: new Roo.data.SimpleStore({
39478 data : this.formats // from states.js
39481 //autoCreate : {tag: "div", size: "20"},
39482 displayField:'tag',
39486 triggerAction: 'all',
39487 emptyText:'Add tag',
39488 selectOnFocus:true,
39491 'select': function(c, r, i) {
39492 editor.insertTag(r.get('tag'));
39498 tb.addField(this.formatCombo);
39502 if(!this.disable.format){
39509 if(!this.disable.fontSize){
39514 btn('increasefontsize', false, editor.adjustFont),
39515 btn('decreasefontsize', false, editor.adjustFont)
39520 if(this.disable.colors){
39523 id:editor.frameId +'-forecolor',
39524 cls:'x-btn-icon x-edit-forecolor',
39525 clickEvent:'mousedown',
39526 tooltip: this.buttonTips['forecolor'] || undefined,
39528 menu : new Roo.menu.ColorMenu({
39529 allowReselect: true,
39530 focus: Roo.emptyFn,
39533 selectHandler: function(cp, color){
39534 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39535 editor.deferFocus();
39538 clickEvent:'mousedown'
39541 id:editor.frameId +'backcolor',
39542 cls:'x-btn-icon x-edit-backcolor',
39543 clickEvent:'mousedown',
39544 tooltip: this.buttonTips['backcolor'] || undefined,
39546 menu : new Roo.menu.ColorMenu({
39547 focus: Roo.emptyFn,
39550 allowReselect: true,
39551 selectHandler: function(cp, color){
39553 editor.execCmd('useCSS', false);
39554 editor.execCmd('hilitecolor', color);
39555 editor.execCmd('useCSS', true);
39556 editor.deferFocus();
39558 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39559 Roo.isSafari || Roo.isIE ? '#'+color : color);
39560 editor.deferFocus();
39564 clickEvent:'mousedown'
39569 // now add all the items...
39572 if(!this.disable.alignments){
39575 btn('justifyleft'),
39576 btn('justifycenter'),
39577 btn('justifyright')
39581 //if(!Roo.isSafari){
39582 if(!this.disable.links){
39585 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39589 if(!this.disable.lists){
39592 btn('insertorderedlist'),
39593 btn('insertunorderedlist')
39596 if(!this.disable.sourceEdit){
39599 btn('sourceedit', true, function(btn){
39600 this.toggleSourceEdit(btn.pressed);
39607 // special menu.. - needs to be tidied up..
39608 if (!this.disable.special) {
39611 cls: 'x-edit-none',
39616 for (var i =0; i < this.specialChars.length; i++) {
39617 smenu.menu.items.push({
39619 html: this.specialChars[i],
39620 handler: function(a,b) {
39621 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39634 for(var i =0; i< this.btns.length;i++) {
39635 var b = this.btns[i];
39636 b.cls = 'x-edit-none';
39645 // disable everything...
39647 this.tb.items.each(function(item){
39648 if(item.id != editor.frameId+ '-sourceedit'){
39652 this.rendered = true;
39654 // the all the btns;
39655 editor.on('editorevent', this.updateToolbar, this);
39656 // other toolbars need to implement this..
39657 //editor.on('editmodechange', this.updateToolbar, this);
39663 * Protected method that will not generally be called directly. It triggers
39664 * a toolbar update by reading the markup state of the current selection in the editor.
39666 updateToolbar: function(){
39668 if(!this.editor.activated){
39669 this.editor.onFirstFocus();
39673 var btns = this.tb.items.map,
39674 doc = this.editor.doc,
39675 frameId = this.editor.frameId;
39677 if(!this.disable.font && !Roo.isSafari){
39679 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39680 if(name != this.fontSelect.dom.value){
39681 this.fontSelect.dom.value = name;
39685 if(!this.disable.format){
39686 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39687 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39688 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39690 if(!this.disable.alignments){
39691 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39692 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39693 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39695 if(!Roo.isSafari && !this.disable.lists){
39696 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39697 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39700 var ans = this.editor.getAllAncestors();
39701 if (this.formatCombo) {
39704 var store = this.formatCombo.store;
39705 this.formatCombo.setValue("");
39706 for (var i =0; i < ans.length;i++) {
39707 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39709 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39717 // hides menus... - so this cant be on a menu...
39718 Roo.menu.MenuMgr.hideAll();
39720 //this.editorsyncValue();
39724 createFontOptions : function(){
39725 var buf = [], fs = this.fontFamilies, ff, lc;
39726 for(var i = 0, len = fs.length; i< len; i++){
39728 lc = ff.toLowerCase();
39730 '<option value="',lc,'" style="font-family:',ff,';"',
39731 (this.defaultFont == lc ? ' selected="true">' : '>'),
39736 return buf.join('');
39739 toggleSourceEdit : function(sourceEditMode){
39740 if(sourceEditMode === undefined){
39741 sourceEditMode = !this.sourceEditMode;
39743 this.sourceEditMode = sourceEditMode === true;
39744 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39745 // just toggle the button?
39746 if(btn.pressed !== this.editor.sourceEditMode){
39747 btn.toggle(this.editor.sourceEditMode);
39751 if(this.sourceEditMode){
39752 this.tb.items.each(function(item){
39753 if(item.cmd != 'sourceedit'){
39759 if(this.initialized){
39760 this.tb.items.each(function(item){
39766 // tell the editor that it's been pressed..
39767 this.editor.toggleSourceEdit(sourceEditMode);
39771 * Object collection of toolbar tooltips for the buttons in the editor. The key
39772 * is the command id associated with that button and the value is a valid QuickTips object.
39777 title: 'Bold (Ctrl+B)',
39778 text: 'Make the selected text bold.',
39779 cls: 'x-html-editor-tip'
39782 title: 'Italic (Ctrl+I)',
39783 text: 'Make the selected text italic.',
39784 cls: 'x-html-editor-tip'
39792 title: 'Bold (Ctrl+B)',
39793 text: 'Make the selected text bold.',
39794 cls: 'x-html-editor-tip'
39797 title: 'Italic (Ctrl+I)',
39798 text: 'Make the selected text italic.',
39799 cls: 'x-html-editor-tip'
39802 title: 'Underline (Ctrl+U)',
39803 text: 'Underline the selected text.',
39804 cls: 'x-html-editor-tip'
39806 increasefontsize : {
39807 title: 'Grow Text',
39808 text: 'Increase the font size.',
39809 cls: 'x-html-editor-tip'
39811 decreasefontsize : {
39812 title: 'Shrink Text',
39813 text: 'Decrease the font size.',
39814 cls: 'x-html-editor-tip'
39817 title: 'Text Highlight Color',
39818 text: 'Change the background color of the selected text.',
39819 cls: 'x-html-editor-tip'
39822 title: 'Font Color',
39823 text: 'Change the color of the selected text.',
39824 cls: 'x-html-editor-tip'
39827 title: 'Align Text Left',
39828 text: 'Align text to the left.',
39829 cls: 'x-html-editor-tip'
39832 title: 'Center Text',
39833 text: 'Center text in the editor.',
39834 cls: 'x-html-editor-tip'
39837 title: 'Align Text Right',
39838 text: 'Align text to the right.',
39839 cls: 'x-html-editor-tip'
39841 insertunorderedlist : {
39842 title: 'Bullet List',
39843 text: 'Start a bulleted list.',
39844 cls: 'x-html-editor-tip'
39846 insertorderedlist : {
39847 title: 'Numbered List',
39848 text: 'Start a numbered list.',
39849 cls: 'x-html-editor-tip'
39852 title: 'Hyperlink',
39853 text: 'Make the selected text a hyperlink.',
39854 cls: 'x-html-editor-tip'
39857 title: 'Source Edit',
39858 text: 'Switch to source editing mode.',
39859 cls: 'x-html-editor-tip'
39863 onDestroy : function(){
39866 this.tb.items.each(function(item){
39868 item.menu.removeAll();
39870 item.menu.el.destroy();
39878 onFirstFocus: function() {
39879 this.tb.items.each(function(item){
39888 // <script type="text/javascript">
39891 * Ext JS Library 1.1.1
39892 * Copyright(c) 2006-2007, Ext JS, LLC.
39899 * @class Roo.form.HtmlEditor.ToolbarContext
39904 new Roo.form.HtmlEditor({
39907 new Roo.form.HtmlEditor.ToolbarStandard(),
39908 new Roo.form.HtmlEditor.ToolbarContext()
39913 * @config : {Object} disable List of elements to disable.. (not done yet.)
39918 Roo.form.HtmlEditor.ToolbarContext = function(config)
39921 Roo.apply(this, config);
39922 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39923 // dont call parent... till later.
39925 Roo.form.HtmlEditor.ToolbarContext.types = {
39937 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39999 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40004 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40068 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40076 * @cfg {Object} disable List of toolbar elements to disable
40085 init : function(editor)
40087 this.editor = editor;
40090 var fid = editor.frameId;
40092 function btn(id, toggle, handler){
40093 var xid = fid + '-'+ id ;
40097 cls : 'x-btn-icon x-edit-'+id,
40098 enableToggle:toggle !== false,
40099 scope: editor, // was editor...
40100 handler:handler||editor.relayBtnCmd,
40101 clickEvent:'mousedown',
40102 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40106 // create a new element.
40107 var wdiv = editor.wrap.createChild({
40109 }, editor.wrap.dom.firstChild.nextSibling, true);
40111 // can we do this more than once??
40113 // stop form submits
40116 // disable everything...
40117 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40118 this.toolbars = {};
40120 for (var i in ty) {
40122 this.toolbars[i] = this.buildToolbar(ty[i],i);
40124 this.tb = this.toolbars.BODY;
40128 this.rendered = true;
40130 // the all the btns;
40131 editor.on('editorevent', this.updateToolbar, this);
40132 // other toolbars need to implement this..
40133 //editor.on('editmodechange', this.updateToolbar, this);
40139 * Protected method that will not generally be called directly. It triggers
40140 * a toolbar update by reading the markup state of the current selection in the editor.
40142 updateToolbar: function(){
40144 if(!this.editor.activated){
40145 this.editor.onFirstFocus();
40150 var ans = this.editor.getAllAncestors();
40153 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40154 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40155 sel = sel ? sel : this.editor.doc.body;
40156 sel = sel.tagName.length ? sel : this.editor.doc.body;
40157 var tn = sel.tagName.toUpperCase();
40158 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40159 tn = sel.tagName.toUpperCase();
40160 if (this.tb.name == tn) {
40161 return; // no change
40164 ///console.log("show: " + tn);
40165 this.tb = this.toolbars[tn];
40167 this.tb.fields.each(function(e) {
40168 e.setValue(sel.getAttribute(e.name));
40170 this.tb.selectedNode = sel;
40173 Roo.menu.MenuMgr.hideAll();
40175 //this.editorsyncValue();
40180 onDestroy : function(){
40183 this.tb.items.each(function(item){
40185 item.menu.removeAll();
40187 item.menu.el.destroy();
40195 onFirstFocus: function() {
40196 // need to do this for all the toolbars..
40197 this.tb.items.each(function(item){
40201 buildToolbar: function(tlist, nm)
40203 var editor = this.editor;
40204 // create a new element.
40205 var wdiv = editor.wrap.createChild({
40207 }, editor.wrap.dom.firstChild.nextSibling, true);
40210 var tb = new Roo.Toolbar(wdiv);
40211 tb.add(nm+ ": ");
40212 for (var i in tlist) {
40213 var item = tlist[i];
40214 tb.add(item.title + ": ");
40219 tb.addField( new Roo.form.ComboBox({
40220 store: new Roo.data.SimpleStore({
40223 data : item.opts // from states.js
40226 displayField:'val',
40230 triggerAction: 'all',
40231 emptyText:'Select',
40232 selectOnFocus:true,
40233 width: item.width ? item.width : 130,
40235 'select': function(c, r, i) {
40236 tb.selectedNode.setAttribute(c.name, r.get('val'));
40247 tb.addField( new Roo.form.TextField({
40250 //allowBlank:false,
40255 tb.addField( new Roo.form.TextField({
40261 'change' : function(f, nv, ov) {
40262 tb.selectedNode.setAttribute(f.name, nv);
40268 tb.el.on('click', function(e){
40269 e.preventDefault(); // what does this do?
40271 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40274 // dont need to disable them... as they will get hidden
40291 * Ext JS Library 1.1.1
40292 * Copyright(c) 2006-2007, Ext JS, LLC.
40294 * Originally Released Under LGPL - original licence link has changed is not relivant.
40297 * <script type="text/javascript">
40301 * @class Roo.form.BasicForm
40302 * @extends Roo.util.Observable
40303 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40305 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40306 * @param {Object} config Configuration options
40308 Roo.form.BasicForm = function(el, config){
40309 this.allItems = [];
40310 this.childForms = [];
40311 Roo.apply(this, config);
40313 * The Roo.form.Field items in this form.
40314 * @type MixedCollection
40318 this.items = new Roo.util.MixedCollection(false, function(o){
40319 return o.id || (o.id = Roo.id());
40323 * @event beforeaction
40324 * Fires before any action is performed. Return false to cancel the action.
40325 * @param {Form} this
40326 * @param {Action} action The action to be performed
40328 beforeaction: true,
40330 * @event actionfailed
40331 * Fires when an action fails.
40332 * @param {Form} this
40333 * @param {Action} action The action that failed
40335 actionfailed : true,
40337 * @event actioncomplete
40338 * Fires when an action is completed.
40339 * @param {Form} this
40340 * @param {Action} action The action that completed
40342 actioncomplete : true
40347 Roo.form.BasicForm.superclass.constructor.call(this);
40350 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40352 * @cfg {String} method
40353 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40356 * @cfg {DataReader} reader
40357 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40358 * This is optional as there is built-in support for processing JSON.
40361 * @cfg {DataReader} errorReader
40362 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40363 * This is completely optional as there is built-in support for processing JSON.
40366 * @cfg {String} url
40367 * The URL to use for form actions if one isn't supplied in the action options.
40370 * @cfg {Boolean} fileUpload
40371 * Set to true if this form is a file upload.
40374 * @cfg {Object} baseParams
40375 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40378 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40383 activeAction : null,
40386 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40387 * or setValues() data instead of when the form was first created.
40389 trackResetOnLoad : false,
40393 * childForms - used for multi-tab forms
40396 childForms : false,
40399 * allItems - full list of fields.
40405 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40406 * element by passing it or its id or mask the form itself by passing in true.
40409 waitMsgTarget : undefined,
40412 initEl : function(el){
40413 this.el = Roo.get(el);
40414 this.id = this.el.id || Roo.id();
40415 this.el.on('submit', this.onSubmit, this);
40416 this.el.addClass('x-form');
40420 onSubmit : function(e){
40425 * Returns true if client-side validation on the form is successful.
40428 isValid : function(){
40430 this.items.each(function(f){
40439 * Returns true if any fields in this form have changed since their original load.
40442 isDirty : function(){
40444 this.items.each(function(f){
40454 * Performs a predefined action (submit or load) or custom actions you define on this form.
40455 * @param {String} actionName The name of the action type
40456 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40457 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40458 * accept other config options):
40460 Property Type Description
40461 ---------------- --------------- ----------------------------------------------------------------------------------
40462 url String The url for the action (defaults to the form's url)
40463 method String The form method to use (defaults to the form's method, or POST if not defined)
40464 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40465 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40466 validate the form on the client (defaults to false)
40468 * @return {BasicForm} this
40470 doAction : function(action, options){
40471 if(typeof action == 'string'){
40472 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40474 if(this.fireEvent('beforeaction', this, action) !== false){
40475 this.beforeAction(action);
40476 action.run.defer(100, action);
40482 * Shortcut to do a submit action.
40483 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40484 * @return {BasicForm} this
40486 submit : function(options){
40487 this.doAction('submit', options);
40492 * Shortcut to do a load action.
40493 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40494 * @return {BasicForm} this
40496 load : function(options){
40497 this.doAction('load', options);
40502 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40503 * @param {Record} record The record to edit
40504 * @return {BasicForm} this
40506 updateRecord : function(record){
40507 record.beginEdit();
40508 var fs = record.fields;
40509 fs.each(function(f){
40510 var field = this.findField(f.name);
40512 record.set(f.name, field.getValue());
40520 * Loads an Roo.data.Record into this form.
40521 * @param {Record} record The record to load
40522 * @return {BasicForm} this
40524 loadRecord : function(record){
40525 this.setValues(record.data);
40530 beforeAction : function(action){
40531 var o = action.options;
40533 if(this.waitMsgTarget === true){
40534 this.el.mask(o.waitMsg, 'x-mask-loading');
40535 }else if(this.waitMsgTarget){
40536 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40537 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
40539 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
40545 afterAction : function(action, success){
40546 this.activeAction = null;
40547 var o = action.options;
40549 if(this.waitMsgTarget === true){
40551 }else if(this.waitMsgTarget){
40552 this.waitMsgTarget.unmask();
40554 Roo.MessageBox.updateProgress(1);
40555 Roo.MessageBox.hide();
40562 Roo.callback(o.success, o.scope, [this, action]);
40563 this.fireEvent('actioncomplete', this, action);
40565 Roo.callback(o.failure, o.scope, [this, action]);
40566 this.fireEvent('actionfailed', this, action);
40571 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40572 * @param {String} id The value to search for
40575 findField : function(id){
40576 var field = this.items.get(id);
40578 this.items.each(function(f){
40579 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40585 return field || null;
40589 * Add a secondary form to this one,
40590 * Used to provide tabbed forms. One form is primary, with hidden values
40591 * which mirror the elements from the other forms.
40593 * @param {Roo.form.Form} form to add.
40596 addForm : function(form)
40599 if (this.childForms.indexOf(form) > -1) {
40603 this.childForms.push(form);
40605 Roo.each(form.allItems, function (fe) {
40607 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40608 if (this.findField(n)) { // already added..
40611 var add = new Roo.form.Hidden({
40614 add.render(this.el);
40621 * Mark fields in this form invalid in bulk.
40622 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40623 * @return {BasicForm} this
40625 markInvalid : function(errors){
40626 if(errors instanceof Array){
40627 for(var i = 0, len = errors.length; i < len; i++){
40628 var fieldError = errors[i];
40629 var f = this.findField(fieldError.id);
40631 f.markInvalid(fieldError.msg);
40637 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40638 field.markInvalid(errors[id]);
40642 Roo.each(this.childForms || [], function (f) {
40643 f.markInvalid(errors);
40650 * Set values for fields in this form in bulk.
40651 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40652 * @return {BasicForm} this
40654 setValues : function(values){
40655 if(values instanceof Array){ // array of objects
40656 for(var i = 0, len = values.length; i < len; i++){
40658 var f = this.findField(v.id);
40660 f.setValue(v.value);
40661 if(this.trackResetOnLoad){
40662 f.originalValue = f.getValue();
40666 }else{ // object hash
40669 if(typeof values[id] != 'function' && (field = this.findField(id))){
40671 if (field.setFromData &&
40672 field.valueField &&
40673 field.displayField &&
40674 // combos' with local stores can
40675 // be queried via setValue()
40676 // to set their value..
40677 (field.store && !field.store.isLocal)
40681 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40682 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40683 field.setFromData(sd);
40686 field.setValue(values[id]);
40690 if(this.trackResetOnLoad){
40691 field.originalValue = field.getValue();
40697 Roo.each(this.childForms || [], function (f) {
40698 f.setValues(values);
40705 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40706 * they are returned as an array.
40707 * @param {Boolean} asString
40710 getValues : function(asString){
40711 if (this.childForms) {
40712 // copy values from the child forms
40713 Roo.each(this.childForms, function (f) {
40714 this.setValues(f.getValues());
40720 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40721 if(asString === true){
40724 return Roo.urlDecode(fs);
40728 * Returns the fields in this form as an object with key/value pairs.
40729 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40732 getFieldValues : function()
40734 if (this.childForms) {
40735 // copy values from the child forms
40736 Roo.each(this.childForms, function (f) {
40737 this.setValues(f.getValues());
40742 this.items.each(function(f){
40743 if (!f.getName()) {
40746 var v = f.getValue();
40747 if ((typeof(v) == 'object') && f.getRawValue) {
40748 v = f.getRawValue() ; // dates..
40750 ret[f.getName()] = v;
40757 * Clears all invalid messages in this form.
40758 * @return {BasicForm} this
40760 clearInvalid : function(){
40761 this.items.each(function(f){
40765 Roo.each(this.childForms || [], function (f) {
40774 * Resets this form.
40775 * @return {BasicForm} this
40777 reset : function(){
40778 this.items.each(function(f){
40782 Roo.each(this.childForms || [], function (f) {
40791 * Add Roo.form components to this form.
40792 * @param {Field} field1
40793 * @param {Field} field2 (optional)
40794 * @param {Field} etc (optional)
40795 * @return {BasicForm} this
40798 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40804 * Removes a field from the items collection (does NOT remove its markup).
40805 * @param {Field} field
40806 * @return {BasicForm} this
40808 remove : function(field){
40809 this.items.remove(field);
40814 * Looks at the fields in this form, checks them for an id attribute,
40815 * and calls applyTo on the existing dom element with that id.
40816 * @return {BasicForm} this
40818 render : function(){
40819 this.items.each(function(f){
40820 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40828 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40829 * @param {Object} values
40830 * @return {BasicForm} this
40832 applyToFields : function(o){
40833 this.items.each(function(f){
40840 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40841 * @param {Object} values
40842 * @return {BasicForm} this
40844 applyIfToFields : function(o){
40845 this.items.each(function(f){
40853 Roo.BasicForm = Roo.form.BasicForm;/*
40855 * Ext JS Library 1.1.1
40856 * Copyright(c) 2006-2007, Ext JS, LLC.
40858 * Originally Released Under LGPL - original licence link has changed is not relivant.
40861 * <script type="text/javascript">
40865 * @class Roo.form.Form
40866 * @extends Roo.form.BasicForm
40867 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40869 * @param {Object} config Configuration options
40871 Roo.form.Form = function(config){
40873 if (config.items) {
40874 xitems = config.items;
40875 delete config.items;
40879 Roo.form.Form.superclass.constructor.call(this, null, config);
40880 this.url = this.url || this.action;
40882 this.root = new Roo.form.Layout(Roo.applyIf({
40886 this.active = this.root;
40888 * Array of all the buttons that have been added to this form via {@link addButton}
40892 this.allItems = [];
40895 * @event clientvalidation
40896 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40897 * @param {Form} this
40898 * @param {Boolean} valid true if the form has passed client-side validation
40900 clientvalidation: true,
40903 * Fires when the form is rendered
40904 * @param {Roo.form.Form} form
40909 if (this.progressUrl) {
40910 // push a hidden field onto the list of fields..
40914 name : 'UPLOAD_IDENTIFIER'
40919 Roo.each(xitems, this.addxtype, this);
40925 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40927 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40930 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40933 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40935 buttonAlign:'center',
40938 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40943 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40944 * This property cascades to child containers if not set.
40949 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40950 * fires a looping event with that state. This is required to bind buttons to the valid
40951 * state using the config value formBind:true on the button.
40953 monitorValid : false,
40956 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40961 * @cfg {String} progressUrl - Url to return progress data
40964 progressUrl : false,
40967 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40968 * fields are added and the column is closed. If no fields are passed the column remains open
40969 * until end() is called.
40970 * @param {Object} config The config to pass to the column
40971 * @param {Field} field1 (optional)
40972 * @param {Field} field2 (optional)
40973 * @param {Field} etc (optional)
40974 * @return Column The column container object
40976 column : function(c){
40977 var col = new Roo.form.Column(c);
40979 if(arguments.length > 1){ // duplicate code required because of Opera
40980 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40987 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40988 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40989 * until end() is called.
40990 * @param {Object} config The config to pass to the fieldset
40991 * @param {Field} field1 (optional)
40992 * @param {Field} field2 (optional)
40993 * @param {Field} etc (optional)
40994 * @return FieldSet The fieldset container object
40996 fieldset : function(c){
40997 var fs = new Roo.form.FieldSet(c);
40999 if(arguments.length > 1){ // duplicate code required because of Opera
41000 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41007 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41008 * fields are added and the container is closed. If no fields are passed the container remains open
41009 * until end() is called.
41010 * @param {Object} config The config to pass to the Layout
41011 * @param {Field} field1 (optional)
41012 * @param {Field} field2 (optional)
41013 * @param {Field} etc (optional)
41014 * @return Layout The container object
41016 container : function(c){
41017 var l = new Roo.form.Layout(c);
41019 if(arguments.length > 1){ // duplicate code required because of Opera
41020 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41027 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41028 * @param {Object} container A Roo.form.Layout or subclass of Layout
41029 * @return {Form} this
41031 start : function(c){
41032 // cascade label info
41033 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41034 this.active.stack.push(c);
41035 c.ownerCt = this.active;
41041 * Closes the current open container
41042 * @return {Form} this
41045 if(this.active == this.root){
41048 this.active = this.active.ownerCt;
41053 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41054 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41055 * as the label of the field.
41056 * @param {Field} field1
41057 * @param {Field} field2 (optional)
41058 * @param {Field} etc. (optional)
41059 * @return {Form} this
41062 this.active.stack.push.apply(this.active.stack, arguments);
41063 this.allItems.push.apply(this.allItems,arguments);
41065 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41066 if(a[i].isFormField){
41071 Roo.form.Form.superclass.add.apply(this, r);
41081 * Find any element that has been added to a form, using it's ID or name
41082 * This can include framesets, columns etc. along with regular fields..
41083 * @param {String} id - id or name to find.
41085 * @return {Element} e - or false if nothing found.
41087 findbyId : function(id)
41093 Ext.each(this.allItems, function(f){
41094 if (f.id == id || f.name == id ){
41105 * Render this form into the passed container. This should only be called once!
41106 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41107 * @return {Form} this
41109 render : function(ct)
41115 var o = this.autoCreate || {
41117 method : this.method || 'POST',
41118 id : this.id || Roo.id()
41120 this.initEl(ct.createChild(o));
41122 this.root.render(this.el);
41126 this.items.each(function(f){
41127 f.render('x-form-el-'+f.id);
41130 if(this.buttons.length > 0){
41131 // tables are required to maintain order and for correct IE layout
41132 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41133 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41134 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41136 var tr = tb.getElementsByTagName('tr')[0];
41137 for(var i = 0, len = this.buttons.length; i < len; i++) {
41138 var b = this.buttons[i];
41139 var td = document.createElement('td');
41140 td.className = 'x-form-btn-td';
41141 b.render(tr.appendChild(td));
41144 if(this.monitorValid){ // initialize after render
41145 this.startMonitoring();
41147 this.fireEvent('rendered', this);
41152 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41153 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41154 * object or a valid Roo.DomHelper element config
41155 * @param {Function} handler The function called when the button is clicked
41156 * @param {Object} scope (optional) The scope of the handler function
41157 * @return {Roo.Button}
41159 addButton : function(config, handler, scope){
41163 minWidth: this.minButtonWidth,
41166 if(typeof config == "string"){
41169 Roo.apply(bc, config);
41171 var btn = new Roo.Button(null, bc);
41172 this.buttons.push(btn);
41177 * Adds a series of form elements (using the xtype property as the factory method.
41178 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41179 * @param {Object} config
41182 addxtype : function()
41184 var ar = Array.prototype.slice.call(arguments, 0);
41186 for(var i = 0; i < ar.length; i++) {
41188 continue; // skip -- if this happends something invalid got sent, we
41189 // should ignore it, as basically that interface element will not show up
41190 // and that should be pretty obvious!!
41193 if (Roo.form[ar[i].xtype]) {
41195 var fe = Roo.factory(ar[i], Roo.form);
41201 fe.store.form = this;
41206 this.allItems.push(fe);
41207 if (fe.items && fe.addxtype) {
41208 fe.addxtype.apply(fe, fe.items);
41218 // console.log('adding ' + ar[i].xtype);
41220 if (ar[i].xtype == 'Button') {
41221 //console.log('adding button');
41222 //console.log(ar[i]);
41223 this.addButton(ar[i]);
41224 this.allItems.push(fe);
41228 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41229 alert('end is not supported on xtype any more, use items');
41231 // //console.log('adding end');
41239 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41240 * option "monitorValid"
41242 startMonitoring : function(){
41245 Roo.TaskMgr.start({
41246 run : this.bindHandler,
41247 interval : this.monitorPoll || 200,
41254 * Stops monitoring of the valid state of this form
41256 stopMonitoring : function(){
41257 this.bound = false;
41261 bindHandler : function(){
41263 return false; // stops binding
41266 this.items.each(function(f){
41267 if(!f.isValid(true)){
41272 for(var i = 0, len = this.buttons.length; i < len; i++){
41273 var btn = this.buttons[i];
41274 if(btn.formBind === true && btn.disabled === valid){
41275 btn.setDisabled(!valid);
41278 this.fireEvent('clientvalidation', this, valid);
41292 Roo.Form = Roo.form.Form;
41295 * Ext JS Library 1.1.1
41296 * Copyright(c) 2006-2007, Ext JS, LLC.
41298 * Originally Released Under LGPL - original licence link has changed is not relivant.
41301 * <script type="text/javascript">
41305 * @class Roo.form.Action
41306 * Internal Class used to handle form actions
41308 * @param {Roo.form.BasicForm} el The form element or its id
41309 * @param {Object} config Configuration options
41313 // define the action interface
41314 Roo.form.Action = function(form, options){
41316 this.options = options || {};
41319 * Client Validation Failed
41322 Roo.form.Action.CLIENT_INVALID = 'client';
41324 * Server Validation Failed
41327 Roo.form.Action.SERVER_INVALID = 'server';
41329 * Connect to Server Failed
41332 Roo.form.Action.CONNECT_FAILURE = 'connect';
41334 * Reading Data from Server Failed
41337 Roo.form.Action.LOAD_FAILURE = 'load';
41339 Roo.form.Action.prototype = {
41341 failureType : undefined,
41342 response : undefined,
41343 result : undefined,
41345 // interface method
41346 run : function(options){
41350 // interface method
41351 success : function(response){
41355 // interface method
41356 handleResponse : function(response){
41360 // default connection failure
41361 failure : function(response){
41362 this.response = response;
41363 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41364 this.form.afterAction(this, false);
41367 processResponse : function(response){
41368 this.response = response;
41369 if(!response.responseText){
41372 this.result = this.handleResponse(response);
41373 return this.result;
41376 // utility functions used internally
41377 getUrl : function(appendParams){
41378 var url = this.options.url || this.form.url || this.form.el.dom.action;
41380 var p = this.getParams();
41382 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41388 getMethod : function(){
41389 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41392 getParams : function(){
41393 var bp = this.form.baseParams;
41394 var p = this.options.params;
41396 if(typeof p == "object"){
41397 p = Roo.urlEncode(Roo.applyIf(p, bp));
41398 }else if(typeof p == 'string' && bp){
41399 p += '&' + Roo.urlEncode(bp);
41402 p = Roo.urlEncode(bp);
41407 createCallback : function(){
41409 success: this.success,
41410 failure: this.failure,
41412 timeout: (this.form.timeout*1000),
41413 upload: this.form.fileUpload ? this.success : undefined
41418 Roo.form.Action.Submit = function(form, options){
41419 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41422 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41425 haveProgress : false,
41426 uploadComplete : false,
41428 // uploadProgress indicator.
41429 uploadProgress : function()
41431 if (!this.form.progressUrl) {
41435 if (!this.haveProgress) {
41436 Roo.MessageBox.progress("Uploading", "Uploading");
41438 if (this.uploadComplete) {
41439 Roo.MessageBox.hide();
41443 this.haveProgress = true;
41445 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41447 var c = new Roo.data.Connection();
41449 url : this.form.progressUrl,
41454 success : function(req){
41455 //console.log(data);
41459 rdata = Roo.decode(req.responseText)
41461 Roo.log("Invalid data from server..");
41465 if (!rdata || !rdata.success) {
41469 var data = rdata.data;
41471 if (this.uploadComplete) {
41472 Roo.MessageBox.hide();
41477 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41478 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41481 this.uploadProgress.defer(2000,this);
41484 failure: function(data) {
41485 Roo.log('progress url failed ');
41496 // run get Values on the form, so it syncs any secondary forms.
41497 this.form.getValues();
41499 var o = this.options;
41500 var method = this.getMethod();
41501 var isPost = method == 'POST';
41502 if(o.clientValidation === false || this.form.isValid()){
41504 if (this.form.progressUrl) {
41505 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41506 (new Date() * 1) + '' + Math.random());
41510 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41511 form:this.form.el.dom,
41512 url:this.getUrl(!isPost),
41514 params:isPost ? this.getParams() : null,
41515 isUpload: this.form.fileUpload
41518 this.uploadProgress();
41520 }else if (o.clientValidation !== false){ // client validation failed
41521 this.failureType = Roo.form.Action.CLIENT_INVALID;
41522 this.form.afterAction(this, false);
41526 success : function(response)
41528 this.uploadComplete= true;
41529 if (this.haveProgress) {
41530 Roo.MessageBox.hide();
41533 var result = this.processResponse(response);
41534 if(result === true || result.success){
41535 this.form.afterAction(this, true);
41539 this.form.markInvalid(result.errors);
41540 this.failureType = Roo.form.Action.SERVER_INVALID;
41542 this.form.afterAction(this, false);
41544 failure : function(response)
41546 this.uploadComplete= true;
41547 if (this.haveProgress) {
41548 Roo.MessageBox.hide();
41551 this.response = response;
41552 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41553 this.form.afterAction(this, false);
41556 handleResponse : function(response){
41557 if(this.form.errorReader){
41558 var rs = this.form.errorReader.read(response);
41561 for(var i = 0, len = rs.records.length; i < len; i++) {
41562 var r = rs.records[i];
41563 errors[i] = r.data;
41566 if(errors.length < 1){
41570 success : rs.success,
41576 ret = Roo.decode(response.responseText);
41580 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41590 Roo.form.Action.Load = function(form, options){
41591 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41592 this.reader = this.form.reader;
41595 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41599 Roo.Ajax.request(Roo.apply(
41600 this.createCallback(), {
41601 method:this.getMethod(),
41602 url:this.getUrl(false),
41603 params:this.getParams()
41607 success : function(response){
41608 var result = this.processResponse(response);
41609 if(result === true || !result.success || !result.data){
41610 this.failureType = Roo.form.Action.LOAD_FAILURE;
41611 this.form.afterAction(this, false);
41614 this.form.clearInvalid();
41615 this.form.setValues(result.data);
41616 this.form.afterAction(this, true);
41619 handleResponse : function(response){
41620 if(this.form.reader){
41621 var rs = this.form.reader.read(response);
41622 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41624 success : rs.success,
41628 return Roo.decode(response.responseText);
41632 Roo.form.Action.ACTION_TYPES = {
41633 'load' : Roo.form.Action.Load,
41634 'submit' : Roo.form.Action.Submit
41637 * Ext JS Library 1.1.1
41638 * Copyright(c) 2006-2007, Ext JS, LLC.
41640 * Originally Released Under LGPL - original licence link has changed is not relivant.
41643 * <script type="text/javascript">
41647 * @class Roo.form.Layout
41648 * @extends Roo.Component
41649 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41651 * @param {Object} config Configuration options
41653 Roo.form.Layout = function(config){
41655 if (config.items) {
41656 xitems = config.items;
41657 delete config.items;
41659 Roo.form.Layout.superclass.constructor.call(this, config);
41661 Roo.each(xitems, this.addxtype, this);
41665 Roo.extend(Roo.form.Layout, Roo.Component, {
41667 * @cfg {String/Object} autoCreate
41668 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41671 * @cfg {String/Object/Function} style
41672 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41673 * a function which returns such a specification.
41676 * @cfg {String} labelAlign
41677 * Valid values are "left," "top" and "right" (defaults to "left")
41680 * @cfg {Number} labelWidth
41681 * Fixed width in pixels of all field labels (defaults to undefined)
41684 * @cfg {Boolean} clear
41685 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41689 * @cfg {String} labelSeparator
41690 * The separator to use after field labels (defaults to ':')
41692 labelSeparator : ':',
41694 * @cfg {Boolean} hideLabels
41695 * True to suppress the display of field labels in this layout (defaults to false)
41697 hideLabels : false,
41700 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41705 onRender : function(ct, position){
41706 if(this.el){ // from markup
41707 this.el = Roo.get(this.el);
41708 }else { // generate
41709 var cfg = this.getAutoCreate();
41710 this.el = ct.createChild(cfg, position);
41713 this.el.applyStyles(this.style);
41715 if(this.labelAlign){
41716 this.el.addClass('x-form-label-'+this.labelAlign);
41718 if(this.hideLabels){
41719 this.labelStyle = "display:none";
41720 this.elementStyle = "padding-left:0;";
41722 if(typeof this.labelWidth == 'number'){
41723 this.labelStyle = "width:"+this.labelWidth+"px;";
41724 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41726 if(this.labelAlign == 'top'){
41727 this.labelStyle = "width:auto;";
41728 this.elementStyle = "padding-left:0;";
41731 var stack = this.stack;
41732 var slen = stack.length;
41734 if(!this.fieldTpl){
41735 var t = new Roo.Template(
41736 '<div class="x-form-item {5}">',
41737 '<label for="{0}" style="{2}">{1}{4}</label>',
41738 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41740 '</div><div class="x-form-clear-left"></div>'
41742 t.disableFormats = true;
41744 Roo.form.Layout.prototype.fieldTpl = t;
41746 for(var i = 0; i < slen; i++) {
41747 if(stack[i].isFormField){
41748 this.renderField(stack[i]);
41750 this.renderComponent(stack[i]);
41755 this.el.createChild({cls:'x-form-clear'});
41760 renderField : function(f){
41761 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41764 f.labelStyle||this.labelStyle||'', //2
41765 this.elementStyle||'', //3
41766 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41767 f.itemCls||this.itemCls||'' //5
41768 ], true).getPrevSibling());
41772 renderComponent : function(c){
41773 c.render(c.isLayout ? this.el : this.el.createChild());
41776 * Adds a object form elements (using the xtype property as the factory method.)
41777 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41778 * @param {Object} config
41780 addxtype : function(o)
41782 // create the lement.
41783 o.form = this.form;
41784 var fe = Roo.factory(o, Roo.form);
41785 this.form.allItems.push(fe);
41786 this.stack.push(fe);
41788 if (fe.isFormField) {
41789 this.form.items.add(fe);
41797 * @class Roo.form.Column
41798 * @extends Roo.form.Layout
41799 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41801 * @param {Object} config Configuration options
41803 Roo.form.Column = function(config){
41804 Roo.form.Column.superclass.constructor.call(this, config);
41807 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41809 * @cfg {Number/String} width
41810 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41813 * @cfg {String/Object} autoCreate
41814 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41818 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41821 onRender : function(ct, position){
41822 Roo.form.Column.superclass.onRender.call(this, ct, position);
41824 this.el.setWidth(this.width);
41831 * @class Roo.form.Row
41832 * @extends Roo.form.Layout
41833 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41835 * @param {Object} config Configuration options
41839 Roo.form.Row = function(config){
41840 Roo.form.Row.superclass.constructor.call(this, config);
41843 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41845 * @cfg {Number/String} width
41846 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41849 * @cfg {Number/String} height
41850 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41852 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41856 onRender : function(ct, position){
41857 //console.log('row render');
41859 var t = new Roo.Template(
41860 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41861 '<label for="{0}" style="{2}">{1}{4}</label>',
41862 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41866 t.disableFormats = true;
41868 Roo.form.Layout.prototype.rowTpl = t;
41870 this.fieldTpl = this.rowTpl;
41872 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41873 var labelWidth = 100;
41875 if ((this.labelAlign != 'top')) {
41876 if (typeof this.labelWidth == 'number') {
41877 labelWidth = this.labelWidth
41879 this.padWidth = 20 + labelWidth;
41883 Roo.form.Column.superclass.onRender.call(this, ct, position);
41885 this.el.setWidth(this.width);
41888 this.el.setHeight(this.height);
41893 renderField : function(f){
41894 f.fieldEl = this.fieldTpl.append(this.el, [
41895 f.id, f.fieldLabel,
41896 f.labelStyle||this.labelStyle||'',
41897 this.elementStyle||'',
41898 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41899 f.itemCls||this.itemCls||'',
41900 f.width ? f.width + this.padWidth : 160 + this.padWidth
41907 * @class Roo.form.FieldSet
41908 * @extends Roo.form.Layout
41909 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41911 * @param {Object} config Configuration options
41913 Roo.form.FieldSet = function(config){
41914 Roo.form.FieldSet.superclass.constructor.call(this, config);
41917 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41919 * @cfg {String} legend
41920 * The text to display as the legend for the FieldSet (defaults to '')
41923 * @cfg {String/Object} autoCreate
41924 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41928 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41931 onRender : function(ct, position){
41932 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
41934 this.setLegend(this.legend);
41939 setLegend : function(text){
41941 this.el.child('legend').update(text);
41946 * Ext JS Library 1.1.1
41947 * Copyright(c) 2006-2007, Ext JS, LLC.
41949 * Originally Released Under LGPL - original licence link has changed is not relivant.
41952 * <script type="text/javascript">
41955 * @class Roo.form.VTypes
41956 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41959 Roo.form.VTypes = function(){
41960 // closure these in so they are only created once.
41961 var alpha = /^[a-zA-Z_]+$/;
41962 var alphanum = /^[a-zA-Z0-9_]+$/;
41963 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41964 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41966 // All these messages and functions are configurable
41969 * The function used to validate email addresses
41970 * @param {String} value The email address
41972 'email' : function(v){
41973 return email.test(v);
41976 * The error text to display when the email validation function returns false
41979 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41981 * The keystroke filter mask to be applied on email input
41984 'emailMask' : /[a-z0-9_\.\-@]/i,
41987 * The function used to validate URLs
41988 * @param {String} value The URL
41990 'url' : function(v){
41991 return url.test(v);
41994 * The error text to display when the url validation function returns false
41997 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42000 * The function used to validate alpha values
42001 * @param {String} value The value
42003 'alpha' : function(v){
42004 return alpha.test(v);
42007 * The error text to display when the alpha validation function returns false
42010 'alphaText' : 'This field should only contain letters and _',
42012 * The keystroke filter mask to be applied on alpha input
42015 'alphaMask' : /[a-z_]/i,
42018 * The function used to validate alphanumeric values
42019 * @param {String} value The value
42021 'alphanum' : function(v){
42022 return alphanum.test(v);
42025 * The error text to display when the alphanumeric validation function returns false
42028 'alphanumText' : 'This field should only contain letters, numbers and _',
42030 * The keystroke filter mask to be applied on alphanumeric input
42033 'alphanumMask' : /[a-z0-9_]/i
42035 }();//<script type="text/javascript">
42038 * @class Roo.form.FCKeditor
42039 * @extends Roo.form.TextArea
42040 * Wrapper around the FCKEditor http://www.fckeditor.net
42042 * Creates a new FCKeditor
42043 * @param {Object} config Configuration options
42045 Roo.form.FCKeditor = function(config){
42046 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42049 * @event editorinit
42050 * Fired when the editor is initialized - you can add extra handlers here..
42051 * @param {FCKeditor} this
42052 * @param {Object} the FCK object.
42059 Roo.form.FCKeditor.editors = { };
42060 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42062 //defaultAutoCreate : {
42063 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42067 * @cfg {Object} fck options - see fck manual for details.
42072 * @cfg {Object} fck toolbar set (Basic or Default)
42074 toolbarSet : 'Basic',
42076 * @cfg {Object} fck BasePath
42078 basePath : '/fckeditor/',
42086 onRender : function(ct, position)
42089 this.defaultAutoCreate = {
42091 style:"width:300px;height:60px;",
42092 autocomplete: "off"
42095 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42098 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42099 if(this.preventScrollbars){
42100 this.el.setStyle("overflow", "hidden");
42102 this.el.setHeight(this.growMin);
42105 //console.log('onrender' + this.getId() );
42106 Roo.form.FCKeditor.editors[this.getId()] = this;
42109 this.replaceTextarea() ;
42113 getEditor : function() {
42114 return this.fckEditor;
42117 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42118 * @param {Mixed} value The value to set
42122 setValue : function(value)
42124 //console.log('setValue: ' + value);
42126 if(typeof(value) == 'undefined') { // not sure why this is happending...
42129 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42131 //if(!this.el || !this.getEditor()) {
42132 // this.value = value;
42133 //this.setValue.defer(100,this,[value]);
42137 if(!this.getEditor()) {
42141 this.getEditor().SetData(value);
42148 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42149 * @return {Mixed} value The field value
42151 getValue : function()
42154 if (this.frame && this.frame.dom.style.display == 'none') {
42155 return Roo.form.FCKeditor.superclass.getValue.call(this);
42158 if(!this.el || !this.getEditor()) {
42160 // this.getValue.defer(100,this);
42165 var value=this.getEditor().GetData();
42166 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42167 return Roo.form.FCKeditor.superclass.getValue.call(this);
42173 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42174 * @return {Mixed} value The field value
42176 getRawValue : function()
42178 if (this.frame && this.frame.dom.style.display == 'none') {
42179 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42182 if(!this.el || !this.getEditor()) {
42183 //this.getRawValue.defer(100,this);
42190 var value=this.getEditor().GetData();
42191 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42192 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42196 setSize : function(w,h) {
42200 //if (this.frame && this.frame.dom.style.display == 'none') {
42201 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42204 //if(!this.el || !this.getEditor()) {
42205 // this.setSize.defer(100,this, [w,h]);
42211 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42213 this.frame.dom.setAttribute('width', w);
42214 this.frame.dom.setAttribute('height', h);
42215 this.frame.setSize(w,h);
42219 toggleSourceEdit : function(value) {
42223 this.el.dom.style.display = value ? '' : 'none';
42224 this.frame.dom.style.display = value ? 'none' : '';
42229 focus: function(tag)
42231 if (this.frame.dom.style.display == 'none') {
42232 return Roo.form.FCKeditor.superclass.focus.call(this);
42234 if(!this.el || !this.getEditor()) {
42235 this.focus.defer(100,this, [tag]);
42242 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42243 this.getEditor().Focus();
42245 if (!this.getEditor().Selection.GetSelection()) {
42246 this.focus.defer(100,this, [tag]);
42251 var r = this.getEditor().EditorDocument.createRange();
42252 r.setStart(tgs[0],0);
42253 r.setEnd(tgs[0],0);
42254 this.getEditor().Selection.GetSelection().removeAllRanges();
42255 this.getEditor().Selection.GetSelection().addRange(r);
42256 this.getEditor().Focus();
42263 replaceTextarea : function()
42265 if ( document.getElementById( this.getId() + '___Frame' ) )
42267 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42269 // We must check the elements firstly using the Id and then the name.
42270 var oTextarea = document.getElementById( this.getId() );
42272 var colElementsByName = document.getElementsByName( this.getId() ) ;
42274 oTextarea.style.display = 'none' ;
42276 if ( oTextarea.tabIndex ) {
42277 this.TabIndex = oTextarea.tabIndex ;
42280 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42281 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42282 this.frame = Roo.get(this.getId() + '___Frame')
42285 _getConfigHtml : function()
42289 for ( var o in this.fckconfig ) {
42290 sConfig += sConfig.length > 0 ? '&' : '';
42291 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42294 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42298 _getIFrameHtml : function()
42300 var sFile = 'fckeditor.html' ;
42301 /* no idea what this is about..
42304 if ( (/fcksource=true/i).test( window.top.location.search ) )
42305 sFile = 'fckeditor.original.html' ;
42310 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42311 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42314 var html = '<iframe id="' + this.getId() +
42315 '___Frame" src="' + sLink +
42316 '" width="' + this.width +
42317 '" height="' + this.height + '"' +
42318 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42319 ' frameborder="0" scrolling="no"></iframe>' ;
42324 _insertHtmlBefore : function( html, element )
42326 if ( element.insertAdjacentHTML ) {
42328 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42330 var oRange = document.createRange() ;
42331 oRange.setStartBefore( element ) ;
42332 var oFragment = oRange.createContextualFragment( html );
42333 element.parentNode.insertBefore( oFragment, element ) ;
42346 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42348 function FCKeditor_OnComplete(editorInstance){
42349 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42350 f.fckEditor = editorInstance;
42351 //console.log("loaded");
42352 f.fireEvent('editorinit', f, editorInstance);
42372 //<script type="text/javascript">
42374 * @class Roo.form.GridField
42375 * @extends Roo.form.Field
42376 * Embed a grid (or editable grid into a form)
42379 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42381 * xgrid.store = Roo.data.Store
42382 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42383 * xgrid.store.reader = Roo.data.JsonReader
42387 * Creates a new GridField
42388 * @param {Object} config Configuration options
42390 Roo.form.GridField = function(config){
42391 Roo.form.GridField.superclass.constructor.call(this, config);
42395 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42397 * @cfg {Number} width - used to restrict width of grid..
42401 * @cfg {Number} height - used to restrict height of grid..
42405 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42411 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42412 * {tag: "input", type: "checkbox", autocomplete: "off"})
42414 // defaultAutoCreate : { tag: 'div' },
42415 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42417 * @cfg {String} addTitle Text to include for adding a title.
42421 onResize : function(){
42422 Roo.form.Field.superclass.onResize.apply(this, arguments);
42425 initEvents : function(){
42426 // Roo.form.Checkbox.superclass.initEvents.call(this);
42427 // has no events...
42432 getResizeEl : function(){
42436 getPositionEl : function(){
42441 onRender : function(ct, position){
42443 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42444 var style = this.style;
42447 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42448 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42449 this.viewEl = this.wrap.createChild({ tag: 'div' });
42451 this.viewEl.applyStyles(style);
42454 this.viewEl.setWidth(this.width);
42457 this.viewEl.setHeight(this.height);
42459 //if(this.inputValue !== undefined){
42460 //this.setValue(this.value);
42463 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42466 this.grid.render();
42467 this.grid.getDataSource().on('remove', this.refreshValue, this);
42468 this.grid.getDataSource().on('update', this.refreshValue, this);
42469 this.grid.on('afteredit', this.refreshValue, this);
42475 * Sets the value of the item.
42476 * @param {String} either an object or a string..
42478 setValue : function(v){
42480 v = v || []; // empty set..
42481 // this does not seem smart - it really only affects memoryproxy grids..
42482 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42483 var ds = this.grid.getDataSource();
42484 // assumes a json reader..
42486 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42487 ds.loadData( data);
42489 Roo.form.GridField.superclass.setValue.call(this, v);
42490 this.refreshValue();
42491 // should load data in the grid really....
42495 refreshValue: function() {
42497 this.grid.getDataSource().each(function(r) {
42500 this.el.dom.value = Roo.encode(val);
42508 * Ext JS Library 1.1.1
42509 * Copyright(c) 2006-2007, Ext JS, LLC.
42511 * Originally Released Under LGPL - original licence link has changed is not relivant.
42514 * <script type="text/javascript">
42517 * @class Roo.form.DisplayField
42518 * @extends Roo.form.Field
42519 * A generic Field to display non-editable data.
42521 * Creates a new Display Field item.
42522 * @param {Object} config Configuration options
42524 Roo.form.DisplayField = function(config){
42525 Roo.form.DisplayField.superclass.constructor.call(this, config);
42529 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42530 inputType: 'hidden',
42536 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42538 focusClass : undefined,
42540 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42542 fieldClass: 'x-form-field',
42545 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42547 valueRenderer: undefined,
42551 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42552 * {tag: "input", type: "checkbox", autocomplete: "off"})
42555 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42557 onResize : function(){
42558 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42562 initEvents : function(){
42563 // Roo.form.Checkbox.superclass.initEvents.call(this);
42564 // has no events...
42569 getResizeEl : function(){
42573 getPositionEl : function(){
42578 onRender : function(ct, position){
42580 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42581 //if(this.inputValue !== undefined){
42582 this.wrap = this.el.wrap();
42584 this.viewEl = this.wrap.createChild({ tag: 'div'});
42586 if (this.bodyStyle) {
42587 this.viewEl.applyStyles(this.bodyStyle);
42589 //this.viewEl.setStyle('padding', '2px');
42591 this.setValue(this.value);
42596 initValue : Roo.emptyFn,
42601 onClick : function(){
42606 * Sets the checked state of the checkbox.
42607 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42609 setValue : function(v){
42611 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42612 // this might be called before we have a dom element..
42613 if (!this.viewEl) {
42616 this.viewEl.dom.innerHTML = html;
42617 Roo.form.DisplayField.superclass.setValue.call(this, v);
42620 });//<script type="text/javasscript">
42624 * @class Roo.DDView
42625 * A DnD enabled version of Roo.View.
42626 * @param {Element/String} container The Element in which to create the View.
42627 * @param {String} tpl The template string used to create the markup for each element of the View
42628 * @param {Object} config The configuration properties. These include all the config options of
42629 * {@link Roo.View} plus some specific to this class.<br>
42631 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42632 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42634 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42635 .x-view-drag-insert-above {
42636 border-top:1px dotted #3366cc;
42638 .x-view-drag-insert-below {
42639 border-bottom:1px dotted #3366cc;
42645 Roo.DDView = function(container, tpl, config) {
42646 Roo.DDView.superclass.constructor.apply(this, arguments);
42647 this.getEl().setStyle("outline", "0px none");
42648 this.getEl().unselectable();
42649 if (this.dragGroup) {
42650 this.setDraggable(this.dragGroup.split(","));
42652 if (this.dropGroup) {
42653 this.setDroppable(this.dropGroup.split(","));
42655 if (this.deletable) {
42656 this.setDeletable();
42658 this.isDirtyFlag = false;
42664 Roo.extend(Roo.DDView, Roo.View, {
42665 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42666 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42667 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42668 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42672 reset: Roo.emptyFn,
42674 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42676 validate: function() {
42680 destroy: function() {
42681 this.purgeListeners();
42682 this.getEl.removeAllListeners();
42683 this.getEl().remove();
42684 if (this.dragZone) {
42685 if (this.dragZone.destroy) {
42686 this.dragZone.destroy();
42689 if (this.dropZone) {
42690 if (this.dropZone.destroy) {
42691 this.dropZone.destroy();
42696 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
42697 getName: function() {
42701 /** Loads the View from a JSON string representing the Records to put into the Store. */
42702 setValue: function(v) {
42704 throw "DDView.setValue(). DDView must be constructed with a valid Store";
42707 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
42708 this.store.proxy = new Roo.data.MemoryProxy(data);
42712 /** @return {String} a parenthesised list of the ids of the Records in the View. */
42713 getValue: function() {
42715 this.store.each(function(rec) {
42716 result += rec.id + ',';
42718 return result.substr(0, result.length - 1) + ')';
42721 getIds: function() {
42722 var i = 0, result = new Array(this.store.getCount());
42723 this.store.each(function(rec) {
42724 result[i++] = rec.id;
42729 isDirty: function() {
42730 return this.isDirtyFlag;
42734 * Part of the Roo.dd.DropZone interface. If no target node is found, the
42735 * whole Element becomes the target, and this causes the drop gesture to append.
42737 getTargetFromEvent : function(e) {
42738 var target = e.getTarget();
42739 while ((target !== null) && (target.parentNode != this.el.dom)) {
42740 target = target.parentNode;
42743 target = this.el.dom.lastChild || this.el.dom;
42749 * Create the drag data which consists of an object which has the property "ddel" as
42750 * the drag proxy element.
42752 getDragData : function(e) {
42753 var target = this.findItemFromChild(e.getTarget());
42755 this.handleSelection(e);
42756 var selNodes = this.getSelectedNodes();
42759 copy: this.copy || (this.allowCopy && e.ctrlKey),
42763 var selectedIndices = this.getSelectedIndexes();
42764 for (var i = 0; i < selectedIndices.length; i++) {
42765 dragData.records.push(this.store.getAt(selectedIndices[i]));
42767 if (selNodes.length == 1) {
42768 dragData.ddel = target.cloneNode(true); // the div element
42770 var div = document.createElement('div'); // create the multi element drag "ghost"
42771 div.className = 'multi-proxy';
42772 for (var i = 0, len = selNodes.length; i < len; i++) {
42773 div.appendChild(selNodes[i].cloneNode(true));
42775 dragData.ddel = div;
42777 //console.log(dragData)
42778 //console.log(dragData.ddel.innerHTML)
42781 //console.log('nodragData')
42785 /** Specify to which ddGroup items in this DDView may be dragged. */
42786 setDraggable: function(ddGroup) {
42787 if (ddGroup instanceof Array) {
42788 Roo.each(ddGroup, this.setDraggable, this);
42791 if (this.dragZone) {
42792 this.dragZone.addToGroup(ddGroup);
42794 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
42795 containerScroll: true,
42799 // Draggability implies selection. DragZone's mousedown selects the element.
42800 if (!this.multiSelect) { this.singleSelect = true; }
42802 // Wire the DragZone's handlers up to methods in *this*
42803 this.dragZone.getDragData = this.getDragData.createDelegate(this);
42807 /** Specify from which ddGroup this DDView accepts drops. */
42808 setDroppable: function(ddGroup) {
42809 if (ddGroup instanceof Array) {
42810 Roo.each(ddGroup, this.setDroppable, this);
42813 if (this.dropZone) {
42814 this.dropZone.addToGroup(ddGroup);
42816 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
42817 containerScroll: true,
42821 // Wire the DropZone's handlers up to methods in *this*
42822 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
42823 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
42824 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
42825 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
42826 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
42830 /** Decide whether to drop above or below a View node. */
42831 getDropPoint : function(e, n, dd){
42832 if (n == this.el.dom) { return "above"; }
42833 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
42834 var c = t + (b - t) / 2;
42835 var y = Roo.lib.Event.getPageY(e);
42843 onNodeEnter : function(n, dd, e, data){
42847 onNodeOver : function(n, dd, e, data){
42848 var pt = this.getDropPoint(e, n, dd);
42849 // set the insert point style on the target node
42850 var dragElClass = this.dropNotAllowed;
42853 if (pt == "above"){
42854 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
42855 targetElClass = "x-view-drag-insert-above";
42857 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
42858 targetElClass = "x-view-drag-insert-below";
42860 if (this.lastInsertClass != targetElClass){
42861 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
42862 this.lastInsertClass = targetElClass;
42865 return dragElClass;
42868 onNodeOut : function(n, dd, e, data){
42869 this.removeDropIndicators(n);
42872 onNodeDrop : function(n, dd, e, data){
42873 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
42876 var pt = this.getDropPoint(e, n, dd);
42877 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
42878 if (pt == "below") { insertAt++; }
42879 for (var i = 0; i < data.records.length; i++) {
42880 var r = data.records[i];
42881 var dup = this.store.getById(r.id);
42882 if (dup && (dd != this.dragZone)) {
42883 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
42886 this.store.insert(insertAt++, r.copy());
42888 data.source.isDirtyFlag = true;
42890 this.store.insert(insertAt++, r);
42892 this.isDirtyFlag = true;
42895 this.dragZone.cachedTarget = null;
42899 removeDropIndicators : function(n){
42901 Roo.fly(n).removeClass([
42902 "x-view-drag-insert-above",
42903 "x-view-drag-insert-below"]);
42904 this.lastInsertClass = "_noclass";
42909 * Utility method. Add a delete option to the DDView's context menu.
42910 * @param {String} imageUrl The URL of the "delete" icon image.
42912 setDeletable: function(imageUrl) {
42913 if (!this.singleSelect && !this.multiSelect) {
42914 this.singleSelect = true;
42916 var c = this.getContextMenu();
42917 this.contextMenu.on("itemclick", function(item) {
42920 this.remove(this.getSelectedIndexes());
42924 this.contextMenu.add({
42931 /** Return the context menu for this DDView. */
42932 getContextMenu: function() {
42933 if (!this.contextMenu) {
42934 // Create the View's context menu
42935 this.contextMenu = new Roo.menu.Menu({
42936 id: this.id + "-contextmenu"
42938 this.el.on("contextmenu", this.showContextMenu, this);
42940 return this.contextMenu;
42943 disableContextMenu: function() {
42944 if (this.contextMenu) {
42945 this.el.un("contextmenu", this.showContextMenu, this);
42949 showContextMenu: function(e, item) {
42950 item = this.findItemFromChild(e.getTarget());
42953 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
42954 this.contextMenu.showAt(e.getXY());
42959 * Remove {@link Roo.data.Record}s at the specified indices.
42960 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42962 remove: function(selectedIndices) {
42963 selectedIndices = [].concat(selectedIndices);
42964 for (var i = 0; i < selectedIndices.length; i++) {
42965 var rec = this.store.getAt(selectedIndices[i]);
42966 this.store.remove(rec);
42971 * Double click fires the event, but also, if this is draggable, and there is only one other
42972 * related DropZone, it transfers the selected node.
42974 onDblClick : function(e){
42975 var item = this.findItemFromChild(e.getTarget());
42977 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
42980 if (this.dragGroup) {
42981 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
42982 while (targets.indexOf(this.dropZone) > -1) {
42983 targets.remove(this.dropZone);
42985 if (targets.length == 1) {
42986 this.dragZone.cachedTarget = null;
42987 var el = Roo.get(targets[0].getEl());
42988 var box = el.getBox(true);
42989 targets[0].onNodeDrop(el.dom, {
42991 xy: [box.x, box.y + box.height - 1]
42992 }, null, this.getDragData(e));
42998 handleSelection: function(e) {
42999 this.dragZone.cachedTarget = null;
43000 var item = this.findItemFromChild(e.getTarget());
43002 this.clearSelections(true);
43005 if (item && (this.multiSelect || this.singleSelect)){
43006 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
43007 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
43008 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
43009 this.unselect(item);
43011 this.select(item, this.multiSelect && e.ctrlKey);
43012 this.lastSelection = item;
43017 onItemClick : function(item, index, e){
43018 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43024 unselect : function(nodeInfo, suppressEvent){
43025 var node = this.getNode(nodeInfo);
43026 if(node && this.isSelected(node)){
43027 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43028 Roo.fly(node).removeClass(this.selectedClass);
43029 this.selections.remove(node);
43030 if(!suppressEvent){
43031 this.fireEvent("selectionchange", this, this.selections);
43039 * Ext JS Library 1.1.1
43040 * Copyright(c) 2006-2007, Ext JS, LLC.
43042 * Originally Released Under LGPL - original licence link has changed is not relivant.
43045 * <script type="text/javascript">
43049 * @class Roo.LayoutManager
43050 * @extends Roo.util.Observable
43051 * Base class for layout managers.
43053 Roo.LayoutManager = function(container, config){
43054 Roo.LayoutManager.superclass.constructor.call(this);
43055 this.el = Roo.get(container);
43056 // ie scrollbar fix
43057 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43058 document.body.scroll = "no";
43059 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43060 this.el.position('relative');
43062 this.id = this.el.id;
43063 this.el.addClass("x-layout-container");
43064 /** false to disable window resize monitoring @type Boolean */
43065 this.monitorWindowResize = true;
43070 * Fires when a layout is performed.
43071 * @param {Roo.LayoutManager} this
43075 * @event regionresized
43076 * Fires when the user resizes a region.
43077 * @param {Roo.LayoutRegion} region The resized region
43078 * @param {Number} newSize The new size (width for east/west, height for north/south)
43080 "regionresized" : true,
43082 * @event regioncollapsed
43083 * Fires when a region is collapsed.
43084 * @param {Roo.LayoutRegion} region The collapsed region
43086 "regioncollapsed" : true,
43088 * @event regionexpanded
43089 * Fires when a region is expanded.
43090 * @param {Roo.LayoutRegion} region The expanded region
43092 "regionexpanded" : true
43094 this.updating = false;
43095 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43098 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43100 * Returns true if this layout is currently being updated
43101 * @return {Boolean}
43103 isUpdating : function(){
43104 return this.updating;
43108 * Suspend the LayoutManager from doing auto-layouts while
43109 * making multiple add or remove calls
43111 beginUpdate : function(){
43112 this.updating = true;
43116 * Restore auto-layouts and optionally disable the manager from performing a layout
43117 * @param {Boolean} noLayout true to disable a layout update
43119 endUpdate : function(noLayout){
43120 this.updating = false;
43126 layout: function(){
43130 onRegionResized : function(region, newSize){
43131 this.fireEvent("regionresized", region, newSize);
43135 onRegionCollapsed : function(region){
43136 this.fireEvent("regioncollapsed", region);
43139 onRegionExpanded : function(region){
43140 this.fireEvent("regionexpanded", region);
43144 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43145 * performs box-model adjustments.
43146 * @return {Object} The size as an object {width: (the width), height: (the height)}
43148 getViewSize : function(){
43150 if(this.el.dom != document.body){
43151 size = this.el.getSize();
43153 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43155 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43156 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43161 * Returns the Element this layout is bound to.
43162 * @return {Roo.Element}
43164 getEl : function(){
43169 * Returns the specified region.
43170 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43171 * @return {Roo.LayoutRegion}
43173 getRegion : function(target){
43174 return this.regions[target.toLowerCase()];
43177 onWindowResize : function(){
43178 if(this.monitorWindowResize){
43184 * Ext JS Library 1.1.1
43185 * Copyright(c) 2006-2007, Ext JS, LLC.
43187 * Originally Released Under LGPL - original licence link has changed is not relivant.
43190 * <script type="text/javascript">
43193 * @class Roo.BorderLayout
43194 * @extends Roo.LayoutManager
43195 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43196 * please see: <br><br>
43197 * <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>
43198 * <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>
43201 var layout = new Roo.BorderLayout(document.body, {
43235 preferredTabWidth: 150
43240 var CP = Roo.ContentPanel;
43242 layout.beginUpdate();
43243 layout.add("north", new CP("north", "North"));
43244 layout.add("south", new CP("south", {title: "South", closable: true}));
43245 layout.add("west", new CP("west", {title: "West"}));
43246 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43247 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43248 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43249 layout.getRegion("center").showPanel("center1");
43250 layout.endUpdate();
43253 <b>The container the layout is rendered into can be either the body element or any other element.
43254 If it is not the body element, the container needs to either be an absolute positioned element,
43255 or you will need to add "position:relative" to the css of the container. You will also need to specify
43256 the container size if it is not the body element.</b>
43259 * Create a new BorderLayout
43260 * @param {String/HTMLElement/Element} container The container this layout is bound to
43261 * @param {Object} config Configuration options
43263 Roo.BorderLayout = function(container, config){
43264 config = config || {};
43265 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43266 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43267 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43268 var target = this.factory.validRegions[i];
43269 if(config[target]){
43270 this.addRegion(target, config[target]);
43275 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43277 * Creates and adds a new region if it doesn't already exist.
43278 * @param {String} target The target region key (north, south, east, west or center).
43279 * @param {Object} config The regions config object
43280 * @return {BorderLayoutRegion} The new region
43282 addRegion : function(target, config){
43283 if(!this.regions[target]){
43284 var r = this.factory.create(target, this, config);
43285 this.bindRegion(target, r);
43287 return this.regions[target];
43291 bindRegion : function(name, r){
43292 this.regions[name] = r;
43293 r.on("visibilitychange", this.layout, this);
43294 r.on("paneladded", this.layout, this);
43295 r.on("panelremoved", this.layout, this);
43296 r.on("invalidated", this.layout, this);
43297 r.on("resized", this.onRegionResized, this);
43298 r.on("collapsed", this.onRegionCollapsed, this);
43299 r.on("expanded", this.onRegionExpanded, this);
43303 * Performs a layout update.
43305 layout : function(){
43306 if(this.updating) return;
43307 var size = this.getViewSize();
43308 var w = size.width;
43309 var h = size.height;
43314 //var x = 0, y = 0;
43316 var rs = this.regions;
43317 var north = rs["north"];
43318 var south = rs["south"];
43319 var west = rs["west"];
43320 var east = rs["east"];
43321 var center = rs["center"];
43322 //if(this.hideOnLayout){ // not supported anymore
43323 //c.el.setStyle("display", "none");
43325 if(north && north.isVisible()){
43326 var b = north.getBox();
43327 var m = north.getMargins();
43328 b.width = w - (m.left+m.right);
43331 centerY = b.height + b.y + m.bottom;
43332 centerH -= centerY;
43333 north.updateBox(this.safeBox(b));
43335 if(south && south.isVisible()){
43336 var b = south.getBox();
43337 var m = south.getMargins();
43338 b.width = w - (m.left+m.right);
43340 var totalHeight = (b.height + m.top + m.bottom);
43341 b.y = h - totalHeight + m.top;
43342 centerH -= totalHeight;
43343 south.updateBox(this.safeBox(b));
43345 if(west && west.isVisible()){
43346 var b = west.getBox();
43347 var m = west.getMargins();
43348 b.height = centerH - (m.top+m.bottom);
43350 b.y = centerY + m.top;
43351 var totalWidth = (b.width + m.left + m.right);
43352 centerX += totalWidth;
43353 centerW -= totalWidth;
43354 west.updateBox(this.safeBox(b));
43356 if(east && east.isVisible()){
43357 var b = east.getBox();
43358 var m = east.getMargins();
43359 b.height = centerH - (m.top+m.bottom);
43360 var totalWidth = (b.width + m.left + m.right);
43361 b.x = w - totalWidth + m.left;
43362 b.y = centerY + m.top;
43363 centerW -= totalWidth;
43364 east.updateBox(this.safeBox(b));
43367 var m = center.getMargins();
43369 x: centerX + m.left,
43370 y: centerY + m.top,
43371 width: centerW - (m.left+m.right),
43372 height: centerH - (m.top+m.bottom)
43374 //if(this.hideOnLayout){
43375 //center.el.setStyle("display", "block");
43377 center.updateBox(this.safeBox(centerBox));
43380 this.fireEvent("layout", this);
43384 safeBox : function(box){
43385 box.width = Math.max(0, box.width);
43386 box.height = Math.max(0, box.height);
43391 * Adds a ContentPanel (or subclass) to this layout.
43392 * @param {String} target The target region key (north, south, east, west or center).
43393 * @param {Roo.ContentPanel} panel The panel to add
43394 * @return {Roo.ContentPanel} The added panel
43396 add : function(target, panel){
43398 target = target.toLowerCase();
43399 return this.regions[target].add(panel);
43403 * Remove a ContentPanel (or subclass) to this layout.
43404 * @param {String} target The target region key (north, south, east, west or center).
43405 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43406 * @return {Roo.ContentPanel} The removed panel
43408 remove : function(target, panel){
43409 target = target.toLowerCase();
43410 return this.regions[target].remove(panel);
43414 * Searches all regions for a panel with the specified id
43415 * @param {String} panelId
43416 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43418 findPanel : function(panelId){
43419 var rs = this.regions;
43420 for(var target in rs){
43421 if(typeof rs[target] != "function"){
43422 var p = rs[target].getPanel(panelId);
43432 * Searches all regions for a panel with the specified id and activates (shows) it.
43433 * @param {String/ContentPanel} panelId The panels id or the panel itself
43434 * @return {Roo.ContentPanel} The shown panel or null
43436 showPanel : function(panelId) {
43437 var rs = this.regions;
43438 for(var target in rs){
43439 var r = rs[target];
43440 if(typeof r != "function"){
43441 if(r.hasPanel(panelId)){
43442 return r.showPanel(panelId);
43450 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43451 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43453 restoreState : function(provider){
43455 provider = Roo.state.Manager;
43457 var sm = new Roo.LayoutStateManager();
43458 sm.init(this, provider);
43462 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43463 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43464 * a valid ContentPanel config object. Example:
43466 // Create the main layout
43467 var layout = new Roo.BorderLayout('main-ct', {
43478 // Create and add multiple ContentPanels at once via configs
43481 id: 'source-files',
43483 title:'Ext Source Files',
43496 * @param {Object} regions An object containing ContentPanel configs by region name
43498 batchAdd : function(regions){
43499 this.beginUpdate();
43500 for(var rname in regions){
43501 var lr = this.regions[rname];
43503 this.addTypedPanels(lr, regions[rname]);
43510 addTypedPanels : function(lr, ps){
43511 if(typeof ps == 'string'){
43512 lr.add(new Roo.ContentPanel(ps));
43514 else if(ps instanceof Array){
43515 for(var i =0, len = ps.length; i < len; i++){
43516 this.addTypedPanels(lr, ps[i]);
43519 else if(!ps.events){ // raw config?
43521 delete ps.el; // prevent conflict
43522 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43524 else { // panel object assumed!
43529 * Adds a xtype elements to the layout.
43533 xtype : 'ContentPanel',
43540 xtype : 'NestedLayoutPanel',
43546 items : [ ... list of content panels or nested layout panels.. ]
43550 * @param {Object} cfg Xtype definition of item to add.
43552 addxtype : function(cfg)
43554 // basically accepts a pannel...
43555 // can accept a layout region..!?!?
43556 // console.log('BorderLayout add ' + cfg.xtype)
43558 if (!cfg.xtype.match(/Panel$/)) {
43562 var region = cfg.region;
43568 xitems = cfg.items;
43575 case 'ContentPanel': // ContentPanel (el, cfg)
43576 case 'ScrollPanel': // ContentPanel (el, cfg)
43577 if(cfg.autoCreate) {
43578 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43580 var el = this.el.createChild();
43581 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43584 this.add(region, ret);
43588 case 'TreePanel': // our new panel!
43589 cfg.el = this.el.createChild();
43590 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43591 this.add(region, ret);
43594 case 'NestedLayoutPanel':
43595 // create a new Layout (which is a Border Layout...
43596 var el = this.el.createChild();
43597 var clayout = cfg.layout;
43599 clayout.items = clayout.items || [];
43600 // replace this exitems with the clayout ones..
43601 xitems = clayout.items;
43604 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43605 cfg.background = false;
43607 var layout = new Roo.BorderLayout(el, clayout);
43609 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43610 //console.log('adding nested layout panel ' + cfg.toSource());
43611 this.add(region, ret);
43617 // needs grid and region
43619 //var el = this.getRegion(region).el.createChild();
43620 var el = this.el.createChild();
43621 // create the grid first...
43623 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43625 if (region == 'center' && this.active ) {
43626 cfg.background = false;
43628 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43630 this.add(region, ret);
43631 if (cfg.background) {
43632 ret.on('activate', function(gp) {
43633 if (!gp.grid.rendered) {
43646 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43648 // GridPanel (grid, cfg)
43651 this.beginUpdate();
43653 Roo.each(xitems, function(i) {
43663 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43664 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43665 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43666 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43669 var CP = Roo.ContentPanel;
43671 var layout = Roo.BorderLayout.create({
43675 panels: [new CP("north", "North")]
43684 panels: [new CP("west", {title: "West"})]
43693 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
43702 panels: [new CP("south", {title: "South", closable: true})]
43709 preferredTabWidth: 150,
43711 new CP("center1", {title: "Close Me", closable: true}),
43712 new CP("center2", {title: "Center Panel", closable: false})
43717 layout.getRegion("center").showPanel("center1");
43722 Roo.BorderLayout.create = function(config, targetEl){
43723 var layout = new Roo.BorderLayout(targetEl || document.body, config);
43724 layout.beginUpdate();
43725 var regions = Roo.BorderLayout.RegionFactory.validRegions;
43726 for(var j = 0, jlen = regions.length; j < jlen; j++){
43727 var lr = regions[j];
43728 if(layout.regions[lr] && config[lr].panels){
43729 var r = layout.regions[lr];
43730 var ps = config[lr].panels;
43731 layout.addTypedPanels(r, ps);
43734 layout.endUpdate();
43739 Roo.BorderLayout.RegionFactory = {
43741 validRegions : ["north","south","east","west","center"],
43744 create : function(target, mgr, config){
43745 target = target.toLowerCase();
43746 if(config.lightweight || config.basic){
43747 return new Roo.BasicLayoutRegion(mgr, config, target);
43751 return new Roo.NorthLayoutRegion(mgr, config);
43753 return new Roo.SouthLayoutRegion(mgr, config);
43755 return new Roo.EastLayoutRegion(mgr, config);
43757 return new Roo.WestLayoutRegion(mgr, config);
43759 return new Roo.CenterLayoutRegion(mgr, config);
43761 throw 'Layout region "'+target+'" not supported.';
43765 * Ext JS Library 1.1.1
43766 * Copyright(c) 2006-2007, Ext JS, LLC.
43768 * Originally Released Under LGPL - original licence link has changed is not relivant.
43771 * <script type="text/javascript">
43775 * @class Roo.BasicLayoutRegion
43776 * @extends Roo.util.Observable
43777 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
43778 * and does not have a titlebar, tabs or any other features. All it does is size and position
43779 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
43781 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
43783 this.position = pos;
43786 * @scope Roo.BasicLayoutRegion
43790 * @event beforeremove
43791 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
43792 * @param {Roo.LayoutRegion} this
43793 * @param {Roo.ContentPanel} panel The panel
43794 * @param {Object} e The cancel event object
43796 "beforeremove" : true,
43798 * @event invalidated
43799 * Fires when the layout for this region is changed.
43800 * @param {Roo.LayoutRegion} this
43802 "invalidated" : true,
43804 * @event visibilitychange
43805 * Fires when this region is shown or hidden
43806 * @param {Roo.LayoutRegion} this
43807 * @param {Boolean} visibility true or false
43809 "visibilitychange" : true,
43811 * @event paneladded
43812 * Fires when a panel is added.
43813 * @param {Roo.LayoutRegion} this
43814 * @param {Roo.ContentPanel} panel The panel
43816 "paneladded" : true,
43818 * @event panelremoved
43819 * Fires when a panel is removed.
43820 * @param {Roo.LayoutRegion} this
43821 * @param {Roo.ContentPanel} panel The panel
43823 "panelremoved" : true,
43826 * Fires when this region is collapsed.
43827 * @param {Roo.LayoutRegion} this
43829 "collapsed" : true,
43832 * Fires when this region is expanded.
43833 * @param {Roo.LayoutRegion} this
43838 * Fires when this region is slid into view.
43839 * @param {Roo.LayoutRegion} this
43841 "slideshow" : true,
43844 * Fires when this region slides out of view.
43845 * @param {Roo.LayoutRegion} this
43847 "slidehide" : true,
43849 * @event panelactivated
43850 * Fires when a panel is activated.
43851 * @param {Roo.LayoutRegion} this
43852 * @param {Roo.ContentPanel} panel The activated panel
43854 "panelactivated" : true,
43857 * Fires when the user resizes this region.
43858 * @param {Roo.LayoutRegion} this
43859 * @param {Number} newSize The new size (width for east/west, height for north/south)
43863 /** A collection of panels in this region. @type Roo.util.MixedCollection */
43864 this.panels = new Roo.util.MixedCollection();
43865 this.panels.getKey = this.getPanelId.createDelegate(this);
43867 this.activePanel = null;
43868 // ensure listeners are added...
43870 if (config.listeners || config.events) {
43871 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
43872 listeners : config.listeners || {},
43873 events : config.events || {}
43877 if(skipConfig !== true){
43878 this.applyConfig(config);
43882 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
43883 getPanelId : function(p){
43887 applyConfig : function(config){
43888 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43889 this.config = config;
43894 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
43895 * the width, for horizontal (north, south) the height.
43896 * @param {Number} newSize The new width or height
43898 resizeTo : function(newSize){
43899 var el = this.el ? this.el :
43900 (this.activePanel ? this.activePanel.getEl() : null);
43902 switch(this.position){
43905 el.setWidth(newSize);
43906 this.fireEvent("resized", this, newSize);
43910 el.setHeight(newSize);
43911 this.fireEvent("resized", this, newSize);
43917 getBox : function(){
43918 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
43921 getMargins : function(){
43922 return this.margins;
43925 updateBox : function(box){
43927 var el = this.activePanel.getEl();
43928 el.dom.style.left = box.x + "px";
43929 el.dom.style.top = box.y + "px";
43930 this.activePanel.setSize(box.width, box.height);
43934 * Returns the container element for this region.
43935 * @return {Roo.Element}
43937 getEl : function(){
43938 return this.activePanel;
43942 * Returns true if this region is currently visible.
43943 * @return {Boolean}
43945 isVisible : function(){
43946 return this.activePanel ? true : false;
43949 setActivePanel : function(panel){
43950 panel = this.getPanel(panel);
43951 if(this.activePanel && this.activePanel != panel){
43952 this.activePanel.setActiveState(false);
43953 this.activePanel.getEl().setLeftTop(-10000,-10000);
43955 this.activePanel = panel;
43956 panel.setActiveState(true);
43958 panel.setSize(this.box.width, this.box.height);
43960 this.fireEvent("panelactivated", this, panel);
43961 this.fireEvent("invalidated");
43965 * Show the specified panel.
43966 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43967 * @return {Roo.ContentPanel} The shown panel or null
43969 showPanel : function(panel){
43970 if(panel = this.getPanel(panel)){
43971 this.setActivePanel(panel);
43977 * Get the active panel for this region.
43978 * @return {Roo.ContentPanel} The active panel or null
43980 getActivePanel : function(){
43981 return this.activePanel;
43985 * Add the passed ContentPanel(s)
43986 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43987 * @return {Roo.ContentPanel} The panel added (if only one was added)
43989 add : function(panel){
43990 if(arguments.length > 1){
43991 for(var i = 0, len = arguments.length; i < len; i++) {
43992 this.add(arguments[i]);
43996 if(this.hasPanel(panel)){
43997 this.showPanel(panel);
44000 var el = panel.getEl();
44001 if(el.dom.parentNode != this.mgr.el.dom){
44002 this.mgr.el.dom.appendChild(el.dom);
44004 if(panel.setRegion){
44005 panel.setRegion(this);
44007 this.panels.add(panel);
44008 el.setStyle("position", "absolute");
44009 if(!panel.background){
44010 this.setActivePanel(panel);
44011 if(this.config.initialSize && this.panels.getCount()==1){
44012 this.resizeTo(this.config.initialSize);
44015 this.fireEvent("paneladded", this, panel);
44020 * Returns true if the panel is in this region.
44021 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44022 * @return {Boolean}
44024 hasPanel : function(panel){
44025 if(typeof panel == "object"){ // must be panel obj
44026 panel = panel.getId();
44028 return this.getPanel(panel) ? true : false;
44032 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44033 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44034 * @param {Boolean} preservePanel Overrides the config preservePanel option
44035 * @return {Roo.ContentPanel} The panel that was removed
44037 remove : function(panel, preservePanel){
44038 panel = this.getPanel(panel);
44043 this.fireEvent("beforeremove", this, panel, e);
44044 if(e.cancel === true){
44047 var panelId = panel.getId();
44048 this.panels.removeKey(panelId);
44053 * Returns the panel specified or null if it's not in this region.
44054 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44055 * @return {Roo.ContentPanel}
44057 getPanel : function(id){
44058 if(typeof id == "object"){ // must be panel obj
44061 return this.panels.get(id);
44065 * Returns this regions position (north/south/east/west/center).
44068 getPosition: function(){
44069 return this.position;
44073 * Ext JS Library 1.1.1
44074 * Copyright(c) 2006-2007, Ext JS, LLC.
44076 * Originally Released Under LGPL - original licence link has changed is not relivant.
44079 * <script type="text/javascript">
44083 * @class Roo.LayoutRegion
44084 * @extends Roo.BasicLayoutRegion
44085 * This class represents a region in a layout manager.
44086 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44087 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44088 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44089 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44090 * @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})
44091 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44092 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44093 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44094 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44095 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44096 * @cfg {String} title The title for the region (overrides panel titles)
44097 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44098 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44099 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44100 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44101 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44102 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44103 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44104 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44105 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44106 * @cfg {Boolean} showPin True to show a pin button
44107 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44108 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44109 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44110 * @cfg {Number} width For East/West panels
44111 * @cfg {Number} height For North/South panels
44112 * @cfg {Boolean} split To show the splitter
44114 Roo.LayoutRegion = function(mgr, config, pos){
44115 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44116 var dh = Roo.DomHelper;
44117 /** This region's container element
44118 * @type Roo.Element */
44119 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44120 /** This region's title element
44121 * @type Roo.Element */
44123 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44124 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44125 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44127 this.titleEl.enableDisplayMode();
44128 /** This region's title text element
44129 * @type HTMLElement */
44130 this.titleTextEl = this.titleEl.dom.firstChild;
44131 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44132 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44133 this.closeBtn.enableDisplayMode();
44134 this.closeBtn.on("click", this.closeClicked, this);
44135 this.closeBtn.hide();
44137 this.createBody(config);
44138 this.visible = true;
44139 this.collapsed = false;
44141 if(config.hideWhenEmpty){
44143 this.on("paneladded", this.validateVisibility, this);
44144 this.on("panelremoved", this.validateVisibility, this);
44146 this.applyConfig(config);
44149 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44151 createBody : function(){
44152 /** This region's body element
44153 * @type Roo.Element */
44154 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44157 applyConfig : function(c){
44158 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44159 var dh = Roo.DomHelper;
44160 if(c.titlebar !== false){
44161 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44162 this.collapseBtn.on("click", this.collapse, this);
44163 this.collapseBtn.enableDisplayMode();
44165 if(c.showPin === true || this.showPin){
44166 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44167 this.stickBtn.enableDisplayMode();
44168 this.stickBtn.on("click", this.expand, this);
44169 this.stickBtn.hide();
44172 /** This region's collapsed element
44173 * @type Roo.Element */
44174 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44175 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44177 if(c.floatable !== false){
44178 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44179 this.collapsedEl.on("click", this.collapseClick, this);
44182 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44183 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44184 id: "message", unselectable: "on", style:{"float":"left"}});
44185 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44187 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44188 this.expandBtn.on("click", this.expand, this);
44190 if(this.collapseBtn){
44191 this.collapseBtn.setVisible(c.collapsible == true);
44193 this.cmargins = c.cmargins || this.cmargins ||
44194 (this.position == "west" || this.position == "east" ?
44195 {top: 0, left: 2, right:2, bottom: 0} :
44196 {top: 2, left: 0, right:0, bottom: 2});
44197 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44198 this.bottomTabs = c.tabPosition != "top";
44199 this.autoScroll = c.autoScroll || false;
44200 if(this.autoScroll){
44201 this.bodyEl.setStyle("overflow", "auto");
44203 this.bodyEl.setStyle("overflow", "hidden");
44205 //if(c.titlebar !== false){
44206 if((!c.titlebar && !c.title) || c.titlebar === false){
44207 this.titleEl.hide();
44209 this.titleEl.show();
44211 this.titleTextEl.innerHTML = c.title;
44215 this.duration = c.duration || .30;
44216 this.slideDuration = c.slideDuration || .45;
44219 this.collapse(true);
44226 * Returns true if this region is currently visible.
44227 * @return {Boolean}
44229 isVisible : function(){
44230 return this.visible;
44234 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44235 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44237 setCollapsedTitle : function(title){
44238 title = title || " ";
44239 if(this.collapsedTitleTextEl){
44240 this.collapsedTitleTextEl.innerHTML = title;
44244 getBox : function(){
44246 if(!this.collapsed){
44247 b = this.el.getBox(false, true);
44249 b = this.collapsedEl.getBox(false, true);
44254 getMargins : function(){
44255 return this.collapsed ? this.cmargins : this.margins;
44258 highlight : function(){
44259 this.el.addClass("x-layout-panel-dragover");
44262 unhighlight : function(){
44263 this.el.removeClass("x-layout-panel-dragover");
44266 updateBox : function(box){
44268 if(!this.collapsed){
44269 this.el.dom.style.left = box.x + "px";
44270 this.el.dom.style.top = box.y + "px";
44271 this.updateBody(box.width, box.height);
44273 this.collapsedEl.dom.style.left = box.x + "px";
44274 this.collapsedEl.dom.style.top = box.y + "px";
44275 this.collapsedEl.setSize(box.width, box.height);
44278 this.tabs.autoSizeTabs();
44282 updateBody : function(w, h){
44284 this.el.setWidth(w);
44285 w -= this.el.getBorderWidth("rl");
44286 if(this.config.adjustments){
44287 w += this.config.adjustments[0];
44291 this.el.setHeight(h);
44292 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44293 h -= this.el.getBorderWidth("tb");
44294 if(this.config.adjustments){
44295 h += this.config.adjustments[1];
44297 this.bodyEl.setHeight(h);
44299 h = this.tabs.syncHeight(h);
44302 if(this.panelSize){
44303 w = w !== null ? w : this.panelSize.width;
44304 h = h !== null ? h : this.panelSize.height;
44306 if(this.activePanel){
44307 var el = this.activePanel.getEl();
44308 w = w !== null ? w : el.getWidth();
44309 h = h !== null ? h : el.getHeight();
44310 this.panelSize = {width: w, height: h};
44311 this.activePanel.setSize(w, h);
44313 if(Roo.isIE && this.tabs){
44314 this.tabs.el.repaint();
44319 * Returns the container element for this region.
44320 * @return {Roo.Element}
44322 getEl : function(){
44327 * Hides this region.
44330 if(!this.collapsed){
44331 this.el.dom.style.left = "-2000px";
44334 this.collapsedEl.dom.style.left = "-2000px";
44335 this.collapsedEl.hide();
44337 this.visible = false;
44338 this.fireEvent("visibilitychange", this, false);
44342 * Shows this region if it was previously hidden.
44345 if(!this.collapsed){
44348 this.collapsedEl.show();
44350 this.visible = true;
44351 this.fireEvent("visibilitychange", this, true);
44354 closeClicked : function(){
44355 if(this.activePanel){
44356 this.remove(this.activePanel);
44360 collapseClick : function(e){
44362 e.stopPropagation();
44365 e.stopPropagation();
44371 * Collapses this region.
44372 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44374 collapse : function(skipAnim){
44375 if(this.collapsed) return;
44376 this.collapsed = true;
44378 this.split.el.hide();
44380 if(this.config.animate && skipAnim !== true){
44381 this.fireEvent("invalidated", this);
44382 this.animateCollapse();
44384 this.el.setLocation(-20000,-20000);
44386 this.collapsedEl.show();
44387 this.fireEvent("collapsed", this);
44388 this.fireEvent("invalidated", this);
44392 animateCollapse : function(){
44397 * Expands this region if it was previously collapsed.
44398 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44399 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44401 expand : function(e, skipAnim){
44402 if(e) e.stopPropagation();
44403 if(!this.collapsed || this.el.hasActiveFx()) return;
44405 this.afterSlideIn();
44408 this.collapsed = false;
44409 if(this.config.animate && skipAnim !== true){
44410 this.animateExpand();
44414 this.split.el.show();
44416 this.collapsedEl.setLocation(-2000,-2000);
44417 this.collapsedEl.hide();
44418 this.fireEvent("invalidated", this);
44419 this.fireEvent("expanded", this);
44423 animateExpand : function(){
44427 initTabs : function(){
44428 this.bodyEl.setStyle("overflow", "hidden");
44429 var ts = new Roo.TabPanel(this.bodyEl.dom, {
44430 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44431 disableTooltips: this.config.disableTabTips
44433 if(this.config.hideTabs){
44434 ts.stripWrap.setDisplayed(false);
44437 ts.resizeTabs = this.config.resizeTabs === true;
44438 ts.minTabWidth = this.config.minTabWidth || 40;
44439 ts.maxTabWidth = this.config.maxTabWidth || 250;
44440 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44441 ts.monitorResize = false;
44442 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44443 ts.bodyEl.addClass('x-layout-tabs-body');
44444 this.panels.each(this.initPanelAsTab, this);
44447 initPanelAsTab : function(panel){
44448 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44449 this.config.closeOnTab && panel.isClosable());
44450 if(panel.tabTip !== undefined){
44451 ti.setTooltip(panel.tabTip);
44453 ti.on("activate", function(){
44454 this.setActivePanel(panel);
44456 if(this.config.closeOnTab){
44457 ti.on("beforeclose", function(t, e){
44459 this.remove(panel);
44465 updatePanelTitle : function(panel, title){
44466 if(this.activePanel == panel){
44467 this.updateTitle(title);
44470 var ti = this.tabs.getTab(panel.getEl().id);
44472 if(panel.tabTip !== undefined){
44473 ti.setTooltip(panel.tabTip);
44478 updateTitle : function(title){
44479 if(this.titleTextEl && !this.config.title){
44480 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44484 setActivePanel : function(panel){
44485 panel = this.getPanel(panel);
44486 if(this.activePanel && this.activePanel != panel){
44487 this.activePanel.setActiveState(false);
44489 this.activePanel = panel;
44490 panel.setActiveState(true);
44491 if(this.panelSize){
44492 panel.setSize(this.panelSize.width, this.panelSize.height);
44495 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44497 this.updateTitle(panel.getTitle());
44499 this.fireEvent("invalidated", this);
44501 this.fireEvent("panelactivated", this, panel);
44505 * Shows the specified panel.
44506 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44507 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44509 showPanel : function(panel){
44510 if(panel = this.getPanel(panel)){
44512 var tab = this.tabs.getTab(panel.getEl().id);
44513 if(tab.isHidden()){
44514 this.tabs.unhideTab(tab.id);
44518 this.setActivePanel(panel);
44525 * Get the active panel for this region.
44526 * @return {Roo.ContentPanel} The active panel or null
44528 getActivePanel : function(){
44529 return this.activePanel;
44532 validateVisibility : function(){
44533 if(this.panels.getCount() < 1){
44534 this.updateTitle(" ");
44535 this.closeBtn.hide();
44538 if(!this.isVisible()){
44545 * Adds the passed ContentPanel(s) to this region.
44546 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44547 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44549 add : function(panel){
44550 if(arguments.length > 1){
44551 for(var i = 0, len = arguments.length; i < len; i++) {
44552 this.add(arguments[i]);
44556 if(this.hasPanel(panel)){
44557 this.showPanel(panel);
44560 panel.setRegion(this);
44561 this.panels.add(panel);
44562 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44563 this.bodyEl.dom.appendChild(panel.getEl().dom);
44564 if(panel.background !== true){
44565 this.setActivePanel(panel);
44567 this.fireEvent("paneladded", this, panel);
44573 this.initPanelAsTab(panel);
44575 if(panel.background !== true){
44576 this.tabs.activate(panel.getEl().id);
44578 this.fireEvent("paneladded", this, panel);
44583 * Hides the tab for the specified panel.
44584 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44586 hidePanel : function(panel){
44587 if(this.tabs && (panel = this.getPanel(panel))){
44588 this.tabs.hideTab(panel.getEl().id);
44593 * Unhides the tab for a previously hidden panel.
44594 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44596 unhidePanel : function(panel){
44597 if(this.tabs && (panel = this.getPanel(panel))){
44598 this.tabs.unhideTab(panel.getEl().id);
44602 clearPanels : function(){
44603 while(this.panels.getCount() > 0){
44604 this.remove(this.panels.first());
44609 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44610 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44611 * @param {Boolean} preservePanel Overrides the config preservePanel option
44612 * @return {Roo.ContentPanel} The panel that was removed
44614 remove : function(panel, preservePanel){
44615 panel = this.getPanel(panel);
44620 this.fireEvent("beforeremove", this, panel, e);
44621 if(e.cancel === true){
44624 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44625 var panelId = panel.getId();
44626 this.panels.removeKey(panelId);
44628 document.body.appendChild(panel.getEl().dom);
44631 this.tabs.removeTab(panel.getEl().id);
44632 }else if (!preservePanel){
44633 this.bodyEl.dom.removeChild(panel.getEl().dom);
44635 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44636 var p = this.panels.first();
44637 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44638 tempEl.appendChild(p.getEl().dom);
44639 this.bodyEl.update("");
44640 this.bodyEl.dom.appendChild(p.getEl().dom);
44642 this.updateTitle(p.getTitle());
44644 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44645 this.setActivePanel(p);
44647 panel.setRegion(null);
44648 if(this.activePanel == panel){
44649 this.activePanel = null;
44651 if(this.config.autoDestroy !== false && preservePanel !== true){
44652 try{panel.destroy();}catch(e){}
44654 this.fireEvent("panelremoved", this, panel);
44659 * Returns the TabPanel component used by this region
44660 * @return {Roo.TabPanel}
44662 getTabs : function(){
44666 createTool : function(parentEl, className){
44667 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44668 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44669 btn.addClassOnOver("x-layout-tools-button-over");
44674 * Ext JS Library 1.1.1
44675 * Copyright(c) 2006-2007, Ext JS, LLC.
44677 * Originally Released Under LGPL - original licence link has changed is not relivant.
44680 * <script type="text/javascript">
44686 * @class Roo.SplitLayoutRegion
44687 * @extends Roo.LayoutRegion
44688 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44690 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
44691 this.cursor = cursor;
44692 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
44695 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
44696 splitTip : "Drag to resize.",
44697 collapsibleSplitTip : "Drag to resize. Double click to hide.",
44698 useSplitTips : false,
44700 applyConfig : function(config){
44701 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
44704 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
44705 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
44706 /** The SplitBar for this region
44707 * @type Roo.SplitBar */
44708 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
44709 this.split.on("moved", this.onSplitMove, this);
44710 this.split.useShim = config.useShim === true;
44711 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
44712 if(this.useSplitTips){
44713 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
44715 if(config.collapsible){
44716 this.split.el.on("dblclick", this.collapse, this);
44719 if(typeof config.minSize != "undefined"){
44720 this.split.minSize = config.minSize;
44722 if(typeof config.maxSize != "undefined"){
44723 this.split.maxSize = config.maxSize;
44725 if(config.hideWhenEmpty || config.hidden || config.collapsed){
44726 this.hideSplitter();
44731 getHMaxSize : function(){
44732 var cmax = this.config.maxSize || 10000;
44733 var center = this.mgr.getRegion("center");
44734 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
44737 getVMaxSize : function(){
44738 var cmax = this.config.maxSize || 10000;
44739 var center = this.mgr.getRegion("center");
44740 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
44743 onSplitMove : function(split, newSize){
44744 this.fireEvent("resized", this, newSize);
44748 * Returns the {@link Roo.SplitBar} for this region.
44749 * @return {Roo.SplitBar}
44751 getSplitBar : function(){
44756 this.hideSplitter();
44757 Roo.SplitLayoutRegion.superclass.hide.call(this);
44760 hideSplitter : function(){
44762 this.split.el.setLocation(-2000,-2000);
44763 this.split.el.hide();
44769 this.split.el.show();
44771 Roo.SplitLayoutRegion.superclass.show.call(this);
44774 beforeSlide: function(){
44775 if(Roo.isGecko){// firefox overflow auto bug workaround
44776 this.bodyEl.clip();
44777 if(this.tabs) this.tabs.bodyEl.clip();
44778 if(this.activePanel){
44779 this.activePanel.getEl().clip();
44781 if(this.activePanel.beforeSlide){
44782 this.activePanel.beforeSlide();
44788 afterSlide : function(){
44789 if(Roo.isGecko){// firefox overflow auto bug workaround
44790 this.bodyEl.unclip();
44791 if(this.tabs) this.tabs.bodyEl.unclip();
44792 if(this.activePanel){
44793 this.activePanel.getEl().unclip();
44794 if(this.activePanel.afterSlide){
44795 this.activePanel.afterSlide();
44801 initAutoHide : function(){
44802 if(this.autoHide !== false){
44803 if(!this.autoHideHd){
44804 var st = new Roo.util.DelayedTask(this.slideIn, this);
44805 this.autoHideHd = {
44806 "mouseout": function(e){
44807 if(!e.within(this.el, true)){
44811 "mouseover" : function(e){
44817 this.el.on(this.autoHideHd);
44821 clearAutoHide : function(){
44822 if(this.autoHide !== false){
44823 this.el.un("mouseout", this.autoHideHd.mouseout);
44824 this.el.un("mouseover", this.autoHideHd.mouseover);
44828 clearMonitor : function(){
44829 Roo.get(document).un("click", this.slideInIf, this);
44832 // these names are backwards but not changed for compat
44833 slideOut : function(){
44834 if(this.isSlid || this.el.hasActiveFx()){
44837 this.isSlid = true;
44838 if(this.collapseBtn){
44839 this.collapseBtn.hide();
44841 this.closeBtnState = this.closeBtn.getStyle('display');
44842 this.closeBtn.hide();
44844 this.stickBtn.show();
44847 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
44848 this.beforeSlide();
44849 this.el.setStyle("z-index", 10001);
44850 this.el.slideIn(this.getSlideAnchor(), {
44851 callback: function(){
44853 this.initAutoHide();
44854 Roo.get(document).on("click", this.slideInIf, this);
44855 this.fireEvent("slideshow", this);
44862 afterSlideIn : function(){
44863 this.clearAutoHide();
44864 this.isSlid = false;
44865 this.clearMonitor();
44866 this.el.setStyle("z-index", "");
44867 if(this.collapseBtn){
44868 this.collapseBtn.show();
44870 this.closeBtn.setStyle('display', this.closeBtnState);
44872 this.stickBtn.hide();
44874 this.fireEvent("slidehide", this);
44877 slideIn : function(cb){
44878 if(!this.isSlid || this.el.hasActiveFx()){
44882 this.isSlid = false;
44883 this.beforeSlide();
44884 this.el.slideOut(this.getSlideAnchor(), {
44885 callback: function(){
44886 this.el.setLeftTop(-10000, -10000);
44888 this.afterSlideIn();
44896 slideInIf : function(e){
44897 if(!e.within(this.el)){
44902 animateCollapse : function(){
44903 this.beforeSlide();
44904 this.el.setStyle("z-index", 20000);
44905 var anchor = this.getSlideAnchor();
44906 this.el.slideOut(anchor, {
44907 callback : function(){
44908 this.el.setStyle("z-index", "");
44909 this.collapsedEl.slideIn(anchor, {duration:.3});
44911 this.el.setLocation(-10000,-10000);
44913 this.fireEvent("collapsed", this);
44920 animateExpand : function(){
44921 this.beforeSlide();
44922 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
44923 this.el.setStyle("z-index", 20000);
44924 this.collapsedEl.hide({
44927 this.el.slideIn(this.getSlideAnchor(), {
44928 callback : function(){
44929 this.el.setStyle("z-index", "");
44932 this.split.el.show();
44934 this.fireEvent("invalidated", this);
44935 this.fireEvent("expanded", this);
44963 getAnchor : function(){
44964 return this.anchors[this.position];
44967 getCollapseAnchor : function(){
44968 return this.canchors[this.position];
44971 getSlideAnchor : function(){
44972 return this.sanchors[this.position];
44975 getAlignAdj : function(){
44976 var cm = this.cmargins;
44977 switch(this.position){
44993 getExpandAdj : function(){
44994 var c = this.collapsedEl, cm = this.cmargins;
44995 switch(this.position){
44997 return [-(cm.right+c.getWidth()+cm.left), 0];
45000 return [cm.right+c.getWidth()+cm.left, 0];
45003 return [0, -(cm.top+cm.bottom+c.getHeight())];
45006 return [0, cm.top+cm.bottom+c.getHeight()];
45012 * Ext JS Library 1.1.1
45013 * Copyright(c) 2006-2007, Ext JS, LLC.
45015 * Originally Released Under LGPL - original licence link has changed is not relivant.
45018 * <script type="text/javascript">
45021 * These classes are private internal classes
45023 Roo.CenterLayoutRegion = function(mgr, config){
45024 Roo.LayoutRegion.call(this, mgr, config, "center");
45025 this.visible = true;
45026 this.minWidth = config.minWidth || 20;
45027 this.minHeight = config.minHeight || 20;
45030 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45032 // center panel can't be hidden
45036 // center panel can't be hidden
45039 getMinWidth: function(){
45040 return this.minWidth;
45043 getMinHeight: function(){
45044 return this.minHeight;
45049 Roo.NorthLayoutRegion = function(mgr, config){
45050 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45052 this.split.placement = Roo.SplitBar.TOP;
45053 this.split.orientation = Roo.SplitBar.VERTICAL;
45054 this.split.el.addClass("x-layout-split-v");
45056 var size = config.initialSize || config.height;
45057 if(typeof size != "undefined"){
45058 this.el.setHeight(size);
45061 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45062 orientation: Roo.SplitBar.VERTICAL,
45063 getBox : function(){
45064 if(this.collapsed){
45065 return this.collapsedEl.getBox();
45067 var box = this.el.getBox();
45069 box.height += this.split.el.getHeight();
45074 updateBox : function(box){
45075 if(this.split && !this.collapsed){
45076 box.height -= this.split.el.getHeight();
45077 this.split.el.setLeft(box.x);
45078 this.split.el.setTop(box.y+box.height);
45079 this.split.el.setWidth(box.width);
45081 if(this.collapsed){
45082 this.updateBody(box.width, null);
45084 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45088 Roo.SouthLayoutRegion = function(mgr, config){
45089 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45091 this.split.placement = Roo.SplitBar.BOTTOM;
45092 this.split.orientation = Roo.SplitBar.VERTICAL;
45093 this.split.el.addClass("x-layout-split-v");
45095 var size = config.initialSize || config.height;
45096 if(typeof size != "undefined"){
45097 this.el.setHeight(size);
45100 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45101 orientation: Roo.SplitBar.VERTICAL,
45102 getBox : function(){
45103 if(this.collapsed){
45104 return this.collapsedEl.getBox();
45106 var box = this.el.getBox();
45108 var sh = this.split.el.getHeight();
45115 updateBox : function(box){
45116 if(this.split && !this.collapsed){
45117 var sh = this.split.el.getHeight();
45120 this.split.el.setLeft(box.x);
45121 this.split.el.setTop(box.y-sh);
45122 this.split.el.setWidth(box.width);
45124 if(this.collapsed){
45125 this.updateBody(box.width, null);
45127 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45131 Roo.EastLayoutRegion = function(mgr, config){
45132 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45134 this.split.placement = Roo.SplitBar.RIGHT;
45135 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45136 this.split.el.addClass("x-layout-split-h");
45138 var size = config.initialSize || config.width;
45139 if(typeof size != "undefined"){
45140 this.el.setWidth(size);
45143 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45144 orientation: Roo.SplitBar.HORIZONTAL,
45145 getBox : function(){
45146 if(this.collapsed){
45147 return this.collapsedEl.getBox();
45149 var box = this.el.getBox();
45151 var sw = this.split.el.getWidth();
45158 updateBox : function(box){
45159 if(this.split && !this.collapsed){
45160 var sw = this.split.el.getWidth();
45162 this.split.el.setLeft(box.x);
45163 this.split.el.setTop(box.y);
45164 this.split.el.setHeight(box.height);
45167 if(this.collapsed){
45168 this.updateBody(null, box.height);
45170 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45174 Roo.WestLayoutRegion = function(mgr, config){
45175 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45177 this.split.placement = Roo.SplitBar.LEFT;
45178 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45179 this.split.el.addClass("x-layout-split-h");
45181 var size = config.initialSize || config.width;
45182 if(typeof size != "undefined"){
45183 this.el.setWidth(size);
45186 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45187 orientation: Roo.SplitBar.HORIZONTAL,
45188 getBox : function(){
45189 if(this.collapsed){
45190 return this.collapsedEl.getBox();
45192 var box = this.el.getBox();
45194 box.width += this.split.el.getWidth();
45199 updateBox : function(box){
45200 if(this.split && !this.collapsed){
45201 var sw = this.split.el.getWidth();
45203 this.split.el.setLeft(box.x+box.width);
45204 this.split.el.setTop(box.y);
45205 this.split.el.setHeight(box.height);
45207 if(this.collapsed){
45208 this.updateBody(null, box.height);
45210 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45215 * Ext JS Library 1.1.1
45216 * Copyright(c) 2006-2007, Ext JS, LLC.
45218 * Originally Released Under LGPL - original licence link has changed is not relivant.
45221 * <script type="text/javascript">
45226 * Private internal class for reading and applying state
45228 Roo.LayoutStateManager = function(layout){
45229 // default empty state
45238 Roo.LayoutStateManager.prototype = {
45239 init : function(layout, provider){
45240 this.provider = provider;
45241 var state = provider.get(layout.id+"-layout-state");
45243 var wasUpdating = layout.isUpdating();
45245 layout.beginUpdate();
45247 for(var key in state){
45248 if(typeof state[key] != "function"){
45249 var rstate = state[key];
45250 var r = layout.getRegion(key);
45253 r.resizeTo(rstate.size);
45255 if(rstate.collapsed == true){
45258 r.expand(null, true);
45264 layout.endUpdate();
45266 this.state = state;
45268 this.layout = layout;
45269 layout.on("regionresized", this.onRegionResized, this);
45270 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45271 layout.on("regionexpanded", this.onRegionExpanded, this);
45274 storeState : function(){
45275 this.provider.set(this.layout.id+"-layout-state", this.state);
45278 onRegionResized : function(region, newSize){
45279 this.state[region.getPosition()].size = newSize;
45283 onRegionCollapsed : function(region){
45284 this.state[region.getPosition()].collapsed = true;
45288 onRegionExpanded : function(region){
45289 this.state[region.getPosition()].collapsed = false;
45294 * Ext JS Library 1.1.1
45295 * Copyright(c) 2006-2007, Ext JS, LLC.
45297 * Originally Released Under LGPL - original licence link has changed is not relivant.
45300 * <script type="text/javascript">
45303 * @class Roo.ContentPanel
45304 * @extends Roo.util.Observable
45305 * A basic ContentPanel element.
45306 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45307 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45308 * @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
45309 * @cfg {Boolean} closable True if the panel can be closed/removed
45310 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45311 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45312 * @cfg {Toolbar} toolbar A toolbar for this panel
45313 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45314 * @cfg {String} title The title for this panel
45315 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45316 * @cfg {String} url Calls {@link #setUrl} with this value
45317 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45318 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45319 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45321 * Create a new ContentPanel.
45322 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45323 * @param {String/Object} config A string to set only the title or a config object
45324 * @param {String} content (optional) Set the HTML content for this panel
45325 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45327 Roo.ContentPanel = function(el, config, content){
45331 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45335 if (config && config.parentLayout) {
45336 el = config.parentLayout.el.createChild();
45339 if(el.autoCreate){ // xtype is available if this is called from factory
45343 this.el = Roo.get(el);
45344 if(!this.el && config && config.autoCreate){
45345 if(typeof config.autoCreate == "object"){
45346 if(!config.autoCreate.id){
45347 config.autoCreate.id = config.id||el;
45349 this.el = Roo.DomHelper.append(document.body,
45350 config.autoCreate, true);
45352 this.el = Roo.DomHelper.append(document.body,
45353 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45356 this.closable = false;
45357 this.loaded = false;
45358 this.active = false;
45359 if(typeof config == "string"){
45360 this.title = config;
45362 Roo.apply(this, config);
45365 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45366 this.wrapEl = this.el.wrap();
45367 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45374 this.resizeEl = Roo.get(this.resizeEl, true);
45376 this.resizeEl = this.el;
45381 * Fires when this panel is activated.
45382 * @param {Roo.ContentPanel} this
45386 * @event deactivate
45387 * Fires when this panel is activated.
45388 * @param {Roo.ContentPanel} this
45390 "deactivate" : true,
45394 * Fires when this panel is resized if fitToFrame is true.
45395 * @param {Roo.ContentPanel} this
45396 * @param {Number} width The width after any component adjustments
45397 * @param {Number} height The height after any component adjustments
45401 if(this.autoScroll){
45402 this.resizeEl.setStyle("overflow", "auto");
45404 // fix randome scrolling
45405 this.el.on('scroll', function() {
45406 this.scrollTo('top',0);
45409 content = content || this.content;
45411 this.setContent(content);
45413 if(config && config.url){
45414 this.setUrl(this.url, this.params, this.loadOnce);
45419 Roo.ContentPanel.superclass.constructor.call(this);
45422 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45424 setRegion : function(region){
45425 this.region = region;
45427 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45429 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45434 * Returns the toolbar for this Panel if one was configured.
45435 * @return {Roo.Toolbar}
45437 getToolbar : function(){
45438 return this.toolbar;
45441 setActiveState : function(active){
45442 this.active = active;
45444 this.fireEvent("deactivate", this);
45446 this.fireEvent("activate", this);
45450 * Updates this panel's element
45451 * @param {String} content The new content
45452 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45454 setContent : function(content, loadScripts){
45455 this.el.update(content, loadScripts);
45458 ignoreResize : function(w, h){
45459 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45462 this.lastSize = {width: w, height: h};
45467 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45468 * @return {Roo.UpdateManager} The UpdateManager
45470 getUpdateManager : function(){
45471 return this.el.getUpdateManager();
45474 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45475 * @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:
45478 url: "your-url.php",
45479 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45480 callback: yourFunction,
45481 scope: yourObject, //(optional scope)
45484 text: "Loading...",
45489 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45490 * 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.
45491 * @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}
45492 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45493 * @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.
45494 * @return {Roo.ContentPanel} this
45497 var um = this.el.getUpdateManager();
45498 um.update.apply(um, arguments);
45504 * 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.
45505 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45506 * @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)
45507 * @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)
45508 * @return {Roo.UpdateManager} The UpdateManager
45510 setUrl : function(url, params, loadOnce){
45511 if(this.refreshDelegate){
45512 this.removeListener("activate", this.refreshDelegate);
45514 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45515 this.on("activate", this.refreshDelegate);
45516 return this.el.getUpdateManager();
45519 _handleRefresh : function(url, params, loadOnce){
45520 if(!loadOnce || !this.loaded){
45521 var updater = this.el.getUpdateManager();
45522 updater.update(url, params, this._setLoaded.createDelegate(this));
45526 _setLoaded : function(){
45527 this.loaded = true;
45531 * Returns this panel's id
45534 getId : function(){
45539 * Returns this panel's element - used by regiosn to add.
45540 * @return {Roo.Element}
45542 getEl : function(){
45543 return this.wrapEl || this.el;
45546 adjustForComponents : function(width, height){
45547 if(this.resizeEl != this.el){
45548 width -= this.el.getFrameWidth('lr');
45549 height -= this.el.getFrameWidth('tb');
45552 var te = this.toolbar.getEl();
45553 height -= te.getHeight();
45554 te.setWidth(width);
45556 if(this.adjustments){
45557 width += this.adjustments[0];
45558 height += this.adjustments[1];
45560 return {"width": width, "height": height};
45563 setSize : function(width, height){
45564 if(this.fitToFrame && !this.ignoreResize(width, height)){
45565 if(this.fitContainer && this.resizeEl != this.el){
45566 this.el.setSize(width, height);
45568 var size = this.adjustForComponents(width, height);
45569 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45570 this.fireEvent('resize', this, size.width, size.height);
45575 * Returns this panel's title
45578 getTitle : function(){
45583 * Set this panel's title
45584 * @param {String} title
45586 setTitle : function(title){
45587 this.title = title;
45589 this.region.updatePanelTitle(this, title);
45594 * Returns true is this panel was configured to be closable
45595 * @return {Boolean}
45597 isClosable : function(){
45598 return this.closable;
45601 beforeSlide : function(){
45603 this.resizeEl.clip();
45606 afterSlide : function(){
45608 this.resizeEl.unclip();
45612 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45613 * Will fail silently if the {@link #setUrl} method has not been called.
45614 * This does not activate the panel, just updates its content.
45616 refresh : function(){
45617 if(this.refreshDelegate){
45618 this.loaded = false;
45619 this.refreshDelegate();
45624 * Destroys this panel
45626 destroy : function(){
45627 this.el.removeAllListeners();
45628 var tempEl = document.createElement("span");
45629 tempEl.appendChild(this.el.dom);
45630 tempEl.innerHTML = "";
45636 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45646 * @param {Object} cfg Xtype definition of item to add.
45649 addxtype : function(cfg) {
45651 if (cfg.xtype.match(/^Form$/)) {
45652 var el = this.el.createChild();
45654 this.form = new Roo.form.Form(cfg);
45657 if ( this.form.allItems.length) this.form.render(el.dom);
45660 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
45662 cfg.el = this.el.appendChild(document.createElement("div"));
45664 var ret = new Roo[cfg.xtype](cfg);
45665 ret.render(false, ''); // render blank..
45675 * @class Roo.GridPanel
45676 * @extends Roo.ContentPanel
45678 * Create a new GridPanel.
45679 * @param {Roo.grid.Grid} grid The grid for this panel
45680 * @param {String/Object} config A string to set only the panel's title, or a config object
45682 Roo.GridPanel = function(grid, config){
45685 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45686 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45688 this.wrapper.dom.appendChild(grid.getGridEl().dom);
45690 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
45693 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
45695 // xtype created footer. - not sure if will work as we normally have to render first..
45696 if (this.footer && !this.footer.el && this.footer.xtype) {
45698 this.footer.container = this.grid.getView().getFooterPanel(true);
45699 this.footer.dataSource = this.grid.dataSource;
45700 this.footer = Roo.factory(this.footer, Roo);
45704 grid.monitorWindowResize = false; // turn off autosizing
45705 grid.autoHeight = false;
45706 grid.autoWidth = false;
45708 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
45711 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
45712 getId : function(){
45713 return this.grid.id;
45717 * Returns the grid for this panel
45718 * @return {Roo.grid.Grid}
45720 getGrid : function(){
45724 setSize : function(width, height){
45725 if(!this.ignoreResize(width, height)){
45726 var grid = this.grid;
45727 var size = this.adjustForComponents(width, height);
45728 grid.getGridEl().setSize(size.width, size.height);
45733 beforeSlide : function(){
45734 this.grid.getView().scroller.clip();
45737 afterSlide : function(){
45738 this.grid.getView().scroller.unclip();
45741 destroy : function(){
45742 this.grid.destroy();
45744 Roo.GridPanel.superclass.destroy.call(this);
45750 * @class Roo.NestedLayoutPanel
45751 * @extends Roo.ContentPanel
45753 * Create a new NestedLayoutPanel.
45756 * @param {Roo.BorderLayout} layout The layout for this panel
45757 * @param {String/Object} config A string to set only the title or a config object
45759 Roo.NestedLayoutPanel = function(layout, config)
45761 // construct with only one argument..
45762 /* FIXME - implement nicer consturctors
45763 if (layout.layout) {
45765 layout = config.layout;
45766 delete config.layout;
45768 if (layout.xtype && !layout.getEl) {
45769 // then layout needs constructing..
45770 layout = Roo.factory(layout, Roo);
45775 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
45777 layout.monitorWindowResize = false; // turn off autosizing
45778 this.layout = layout;
45779 this.layout.getEl().addClass("x-layout-nested-layout");
45786 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
45788 setSize : function(width, height){
45789 if(!this.ignoreResize(width, height)){
45790 var size = this.adjustForComponents(width, height);
45791 var el = this.layout.getEl();
45792 el.setSize(size.width, size.height);
45793 var touch = el.dom.offsetWidth;
45794 this.layout.layout();
45795 // ie requires a double layout on the first pass
45796 if(Roo.isIE && !this.initialized){
45797 this.initialized = true;
45798 this.layout.layout();
45803 // activate all subpanels if not currently active..
45805 setActiveState : function(active){
45806 this.active = active;
45808 this.fireEvent("deactivate", this);
45812 this.fireEvent("activate", this);
45813 // not sure if this should happen before or after..
45814 if (!this.layout) {
45815 return; // should not happen..
45818 for (var r in this.layout.regions) {
45819 reg = this.layout.getRegion(r);
45820 if (reg.getActivePanel()) {
45821 //reg.showPanel(reg.getActivePanel()); // force it to activate..
45822 reg.setActivePanel(reg.getActivePanel());
45825 if (!reg.panels.length) {
45828 reg.showPanel(reg.getPanel(0));
45837 * Returns the nested BorderLayout for this panel
45838 * @return {Roo.BorderLayout}
45840 getLayout : function(){
45841 return this.layout;
45845 * Adds a xtype elements to the layout of the nested panel
45849 xtype : 'ContentPanel',
45856 xtype : 'NestedLayoutPanel',
45862 items : [ ... list of content panels or nested layout panels.. ]
45866 * @param {Object} cfg Xtype definition of item to add.
45868 addxtype : function(cfg) {
45869 return this.layout.addxtype(cfg);
45874 Roo.ScrollPanel = function(el, config, content){
45875 config = config || {};
45876 config.fitToFrame = true;
45877 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
45879 this.el.dom.style.overflow = "hidden";
45880 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
45881 this.el.removeClass("x-layout-inactive-content");
45882 this.el.on("mousewheel", this.onWheel, this);
45884 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
45885 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
45886 up.unselectable(); down.unselectable();
45887 up.on("click", this.scrollUp, this);
45888 down.on("click", this.scrollDown, this);
45889 up.addClassOnOver("x-scroller-btn-over");
45890 down.addClassOnOver("x-scroller-btn-over");
45891 up.addClassOnClick("x-scroller-btn-click");
45892 down.addClassOnClick("x-scroller-btn-click");
45893 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
45895 this.resizeEl = this.el;
45896 this.el = wrap; this.up = up; this.down = down;
45899 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
45901 wheelIncrement : 5,
45902 scrollUp : function(){
45903 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
45906 scrollDown : function(){
45907 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
45910 afterScroll : function(){
45911 var el = this.resizeEl;
45912 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
45913 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45914 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45917 setSize : function(){
45918 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
45919 this.afterScroll();
45922 onWheel : function(e){
45923 var d = e.getWheelDelta();
45924 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
45925 this.afterScroll();
45929 setContent : function(content, loadScripts){
45930 this.resizeEl.update(content, loadScripts);
45944 * @class Roo.TreePanel
45945 * @extends Roo.ContentPanel
45947 * Create a new TreePanel. - defaults to fit/scoll contents.
45948 * @param {String/Object} config A string to set only the panel's title, or a config object
45949 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
45951 Roo.TreePanel = function(config){
45952 var el = config.el;
45953 var tree = config.tree;
45954 delete config.tree;
45955 delete config.el; // hopefull!
45957 // wrapper for IE7 strict & safari scroll issue
45959 var treeEl = el.createChild();
45960 config.resizeEl = treeEl;
45964 Roo.TreePanel.superclass.constructor.call(this, el, config);
45967 this.tree = new Roo.tree.TreePanel(treeEl , tree);
45968 //console.log(tree);
45969 this.on('activate', function()
45971 if (this.tree.rendered) {
45974 //console.log('render tree');
45975 this.tree.render();
45978 this.on('resize', function (cp, w, h) {
45979 this.tree.innerCt.setWidth(w);
45980 this.tree.innerCt.setHeight(h);
45981 this.tree.innerCt.setStyle('overflow-y', 'auto');
45988 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
46005 * Ext JS Library 1.1.1
46006 * Copyright(c) 2006-2007, Ext JS, LLC.
46008 * Originally Released Under LGPL - original licence link has changed is not relivant.
46011 * <script type="text/javascript">
46016 * @class Roo.ReaderLayout
46017 * @extends Roo.BorderLayout
46018 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46019 * center region containing two nested regions (a top one for a list view and one for item preview below),
46020 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46021 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46022 * expedites the setup of the overall layout and regions for this common application style.
46025 var reader = new Roo.ReaderLayout();
46026 var CP = Roo.ContentPanel; // shortcut for adding
46028 reader.beginUpdate();
46029 reader.add("north", new CP("north", "North"));
46030 reader.add("west", new CP("west", {title: "West"}));
46031 reader.add("east", new CP("east", {title: "East"}));
46033 reader.regions.listView.add(new CP("listView", "List"));
46034 reader.regions.preview.add(new CP("preview", "Preview"));
46035 reader.endUpdate();
46038 * Create a new ReaderLayout
46039 * @param {Object} config Configuration options
46040 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46041 * document.body if omitted)
46043 Roo.ReaderLayout = function(config, renderTo){
46044 var c = config || {size:{}};
46045 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46046 north: c.north !== false ? Roo.apply({
46050 }, c.north) : false,
46051 west: c.west !== false ? Roo.apply({
46059 margins:{left:5,right:0,bottom:5,top:5},
46060 cmargins:{left:5,right:5,bottom:5,top:5}
46061 }, c.west) : false,
46062 east: c.east !== false ? Roo.apply({
46070 margins:{left:0,right:5,bottom:5,top:5},
46071 cmargins:{left:5,right:5,bottom:5,top:5}
46072 }, c.east) : false,
46073 center: Roo.apply({
46074 tabPosition: 'top',
46078 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46082 this.el.addClass('x-reader');
46084 this.beginUpdate();
46086 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46087 south: c.preview !== false ? Roo.apply({
46094 cmargins:{top:5,left:0, right:0, bottom:0}
46095 }, c.preview) : false,
46096 center: Roo.apply({
46102 this.add('center', new Roo.NestedLayoutPanel(inner,
46103 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46107 this.regions.preview = inner.getRegion('south');
46108 this.regions.listView = inner.getRegion('center');
46111 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46113 * Ext JS Library 1.1.1
46114 * Copyright(c) 2006-2007, Ext JS, LLC.
46116 * Originally Released Under LGPL - original licence link has changed is not relivant.
46119 * <script type="text/javascript">
46123 * @class Roo.grid.Grid
46124 * @extends Roo.util.Observable
46125 * This class represents the primary interface of a component based grid control.
46126 * <br><br>Usage:<pre><code>
46127 var grid = new Roo.grid.Grid("my-container-id", {
46130 selModel: mySelectionModel,
46131 autoSizeColumns: true,
46132 monitorWindowResize: false,
46133 trackMouseOver: true
46138 * <b>Common Problems:</b><br/>
46139 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46140 * element will correct this<br/>
46141 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46142 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46143 * are unpredictable.<br/>
46144 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46145 * grid to calculate dimensions/offsets.<br/>
46147 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46148 * The container MUST have some type of size defined for the grid to fill. The container will be
46149 * automatically set to position relative if it isn't already.
46150 * @param {Object} config A config object that sets properties on this grid.
46152 Roo.grid.Grid = function(container, config){
46153 // initialize the container
46154 this.container = Roo.get(container);
46155 this.container.update("");
46156 this.container.setStyle("overflow", "hidden");
46157 this.container.addClass('x-grid-container');
46159 this.id = this.container.id;
46161 Roo.apply(this, config);
46162 // check and correct shorthanded configs
46164 this.dataSource = this.ds;
46168 this.colModel = this.cm;
46172 this.selModel = this.sm;
46176 if (this.selModel) {
46177 this.selModel = Roo.factory(this.selModel, Roo.grid);
46178 this.sm = this.selModel;
46179 this.sm.xmodule = this.xmodule || false;
46181 if (typeof(this.colModel.config) == 'undefined') {
46182 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46183 this.cm = this.colModel;
46184 this.cm.xmodule = this.xmodule || false;
46186 if (this.dataSource) {
46187 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46188 this.ds = this.dataSource;
46189 this.ds.xmodule = this.xmodule || false;
46196 this.container.setWidth(this.width);
46200 this.container.setHeight(this.height);
46207 * The raw click event for the entire grid.
46208 * @param {Roo.EventObject} e
46213 * The raw dblclick event for the entire grid.
46214 * @param {Roo.EventObject} e
46218 * @event contextmenu
46219 * The raw contextmenu event for the entire grid.
46220 * @param {Roo.EventObject} e
46222 "contextmenu" : true,
46225 * The raw mousedown event for the entire grid.
46226 * @param {Roo.EventObject} e
46228 "mousedown" : true,
46231 * The raw mouseup event for the entire grid.
46232 * @param {Roo.EventObject} e
46237 * The raw mouseover event for the entire grid.
46238 * @param {Roo.EventObject} e
46240 "mouseover" : true,
46243 * The raw mouseout event for the entire grid.
46244 * @param {Roo.EventObject} e
46249 * The raw keypress event for the entire grid.
46250 * @param {Roo.EventObject} e
46255 * The raw keydown event for the entire grid.
46256 * @param {Roo.EventObject} e
46264 * Fires when a cell is clicked
46265 * @param {Grid} this
46266 * @param {Number} rowIndex
46267 * @param {Number} columnIndex
46268 * @param {Roo.EventObject} e
46270 "cellclick" : true,
46272 * @event celldblclick
46273 * Fires when a cell is double clicked
46274 * @param {Grid} this
46275 * @param {Number} rowIndex
46276 * @param {Number} columnIndex
46277 * @param {Roo.EventObject} e
46279 "celldblclick" : true,
46282 * Fires when a row is clicked
46283 * @param {Grid} this
46284 * @param {Number} rowIndex
46285 * @param {Roo.EventObject} e
46289 * @event rowdblclick
46290 * Fires when a row is double clicked
46291 * @param {Grid} this
46292 * @param {Number} rowIndex
46293 * @param {Roo.EventObject} e
46295 "rowdblclick" : true,
46297 * @event headerclick
46298 * Fires when a header is clicked
46299 * @param {Grid} this
46300 * @param {Number} columnIndex
46301 * @param {Roo.EventObject} e
46303 "headerclick" : true,
46305 * @event headerdblclick
46306 * Fires when a header cell is double clicked
46307 * @param {Grid} this
46308 * @param {Number} columnIndex
46309 * @param {Roo.EventObject} e
46311 "headerdblclick" : true,
46313 * @event rowcontextmenu
46314 * Fires when a row is right clicked
46315 * @param {Grid} this
46316 * @param {Number} rowIndex
46317 * @param {Roo.EventObject} e
46319 "rowcontextmenu" : true,
46321 * @event cellcontextmenu
46322 * Fires when a cell is right clicked
46323 * @param {Grid} this
46324 * @param {Number} rowIndex
46325 * @param {Number} cellIndex
46326 * @param {Roo.EventObject} e
46328 "cellcontextmenu" : true,
46330 * @event headercontextmenu
46331 * Fires when a header is right clicked
46332 * @param {Grid} this
46333 * @param {Number} columnIndex
46334 * @param {Roo.EventObject} e
46336 "headercontextmenu" : true,
46338 * @event bodyscroll
46339 * Fires when the body element is scrolled
46340 * @param {Number} scrollLeft
46341 * @param {Number} scrollTop
46343 "bodyscroll" : true,
46345 * @event columnresize
46346 * Fires when the user resizes a column
46347 * @param {Number} columnIndex
46348 * @param {Number} newSize
46350 "columnresize" : true,
46352 * @event columnmove
46353 * Fires when the user moves a column
46354 * @param {Number} oldIndex
46355 * @param {Number} newIndex
46357 "columnmove" : true,
46360 * Fires when row(s) start being dragged
46361 * @param {Grid} this
46362 * @param {Roo.GridDD} dd The drag drop object
46363 * @param {event} e The raw browser event
46365 "startdrag" : true,
46368 * Fires when a drag operation is complete
46369 * @param {Grid} this
46370 * @param {Roo.GridDD} dd The drag drop object
46371 * @param {event} e The raw browser event
46376 * Fires when dragged row(s) are dropped on a valid DD target
46377 * @param {Grid} this
46378 * @param {Roo.GridDD} dd The drag drop object
46379 * @param {String} targetId The target drag drop object
46380 * @param {event} e The raw browser event
46385 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46386 * @param {Grid} this
46387 * @param {Roo.GridDD} dd The drag drop object
46388 * @param {String} targetId The target drag drop object
46389 * @param {event} e The raw browser event
46394 * Fires when the dragged row(s) first cross another DD target while being dragged
46395 * @param {Grid} this
46396 * @param {Roo.GridDD} dd The drag drop object
46397 * @param {String} targetId The target drag drop object
46398 * @param {event} e The raw browser event
46400 "dragenter" : true,
46403 * Fires when the dragged row(s) leave another DD target while being dragged
46404 * @param {Grid} this
46405 * @param {Roo.GridDD} dd The drag drop object
46406 * @param {String} targetId The target drag drop object
46407 * @param {event} e The raw browser event
46412 * Fires when the grid is rendered
46413 * @param {Grid} grid
46418 Roo.grid.Grid.superclass.constructor.call(this);
46420 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46423 * @cfg {String} ddGroup - drag drop group.
46427 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46429 minColumnWidth : 25,
46432 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46433 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46434 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46436 autoSizeColumns : false,
46439 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46441 autoSizeHeaders : true,
46444 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46446 monitorWindowResize : true,
46449 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46450 * rows measured to get a columns size. Default is 0 (all rows).
46452 maxRowsToMeasure : 0,
46455 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46457 trackMouseOver : true,
46460 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46464 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46466 enableDragDrop : false,
46469 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46471 enableColumnMove : true,
46474 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46476 enableColumnHide : true,
46479 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46481 enableRowHeightSync : false,
46484 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46489 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46491 autoHeight : false,
46494 * @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.
46496 autoExpandColumn : false,
46499 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46502 autoExpandMin : 50,
46505 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46507 autoExpandMax : 1000,
46510 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46515 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46519 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46526 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46527 * of a fixed width. Default is false.
46530 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46533 * Called once after all setup has been completed and the grid is ready to be rendered.
46534 * @return {Roo.grid.Grid} this
46536 render : function(){
46537 var c = this.container;
46538 // try to detect autoHeight/width mode
46539 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46540 this.autoHeight = true;
46542 var view = this.getView();
46545 c.on("click", this.onClick, this);
46546 c.on("dblclick", this.onDblClick, this);
46547 c.on("contextmenu", this.onContextMenu, this);
46548 c.on("keydown", this.onKeyDown, this);
46550 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46552 this.getSelectionModel().init(this);
46557 this.loadMask = new Roo.LoadMask(this.container,
46558 Roo.apply({store:this.dataSource}, this.loadMask));
46562 if (this.toolbar && this.toolbar.xtype) {
46563 this.toolbar.container = this.getView().getHeaderPanel(true);
46564 this.toolbar = new Ext.Toolbar(this.toolbar);
46566 if (this.footer && this.footer.xtype) {
46567 this.footer.dataSource = this.getDataSource();
46568 this.footer.container = this.getView().getFooterPanel(true);
46569 this.footer = Roo.factory(this.footer, Roo);
46571 if (this.dropTarget && this.dropTarget.xtype) {
46572 delete this.dropTarget.xtype;
46573 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46577 this.rendered = true;
46578 this.fireEvent('render', this);
46583 * Reconfigures the grid to use a different Store and Column Model.
46584 * The View will be bound to the new objects and refreshed.
46585 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46586 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46588 reconfigure : function(dataSource, colModel){
46590 this.loadMask.destroy();
46591 this.loadMask = new Roo.LoadMask(this.container,
46592 Roo.apply({store:dataSource}, this.loadMask));
46594 this.view.bind(dataSource, colModel);
46595 this.dataSource = dataSource;
46596 this.colModel = colModel;
46597 this.view.refresh(true);
46601 onKeyDown : function(e){
46602 this.fireEvent("keydown", e);
46606 * Destroy this grid.
46607 * @param {Boolean} removeEl True to remove the element
46609 destroy : function(removeEl, keepListeners){
46611 this.loadMask.destroy();
46613 var c = this.container;
46614 c.removeAllListeners();
46615 this.view.destroy();
46616 this.colModel.purgeListeners();
46617 if(!keepListeners){
46618 this.purgeListeners();
46621 if(removeEl === true){
46627 processEvent : function(name, e){
46628 this.fireEvent(name, e);
46629 var t = e.getTarget();
46631 var header = v.findHeaderIndex(t);
46632 if(header !== false){
46633 this.fireEvent("header" + name, this, header, e);
46635 var row = v.findRowIndex(t);
46636 var cell = v.findCellIndex(t);
46638 this.fireEvent("row" + name, this, row, e);
46639 if(cell !== false){
46640 this.fireEvent("cell" + name, this, row, cell, e);
46647 onClick : function(e){
46648 this.processEvent("click", e);
46652 onContextMenu : function(e, t){
46653 this.processEvent("contextmenu", e);
46657 onDblClick : function(e){
46658 this.processEvent("dblclick", e);
46662 walkCells : function(row, col, step, fn, scope){
46663 var cm = this.colModel, clen = cm.getColumnCount();
46664 var ds = this.dataSource, rlen = ds.getCount(), first = true;
46676 if(fn.call(scope || this, row, col, cm) === true){
46694 if(fn.call(scope || this, row, col, cm) === true){
46706 getSelections : function(){
46707 return this.selModel.getSelections();
46711 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
46712 * but if manual update is required this method will initiate it.
46714 autoSize : function(){
46716 this.view.layout();
46717 if(this.view.adjustForScroll){
46718 this.view.adjustForScroll();
46724 * Returns the grid's underlying element.
46725 * @return {Element} The element
46727 getGridEl : function(){
46728 return this.container;
46731 // private for compatibility, overridden by editor grid
46732 stopEditing : function(){},
46735 * Returns the grid's SelectionModel.
46736 * @return {SelectionModel}
46738 getSelectionModel : function(){
46739 if(!this.selModel){
46740 this.selModel = new Roo.grid.RowSelectionModel();
46742 return this.selModel;
46746 * Returns the grid's DataSource.
46747 * @return {DataSource}
46749 getDataSource : function(){
46750 return this.dataSource;
46754 * Returns the grid's ColumnModel.
46755 * @return {ColumnModel}
46757 getColumnModel : function(){
46758 return this.colModel;
46762 * Returns the grid's GridView object.
46763 * @return {GridView}
46765 getView : function(){
46767 this.view = new Roo.grid.GridView(this.viewConfig);
46772 * Called to get grid's drag proxy text, by default returns this.ddText.
46775 getDragDropText : function(){
46776 var count = this.selModel.getCount();
46777 return String.format(this.ddText, count, count == 1 ? '' : 's');
46781 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
46782 * %0 is replaced with the number of selected rows.
46785 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
46787 * Ext JS Library 1.1.1
46788 * Copyright(c) 2006-2007, Ext JS, LLC.
46790 * Originally Released Under LGPL - original licence link has changed is not relivant.
46793 * <script type="text/javascript">
46796 Roo.grid.AbstractGridView = function(){
46800 "beforerowremoved" : true,
46801 "beforerowsinserted" : true,
46802 "beforerefresh" : true,
46803 "rowremoved" : true,
46804 "rowsinserted" : true,
46805 "rowupdated" : true,
46808 Roo.grid.AbstractGridView.superclass.constructor.call(this);
46811 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
46812 rowClass : "x-grid-row",
46813 cellClass : "x-grid-cell",
46814 tdClass : "x-grid-td",
46815 hdClass : "x-grid-hd",
46816 splitClass : "x-grid-hd-split",
46818 init: function(grid){
46820 var cid = this.grid.getGridEl().id;
46821 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
46822 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
46823 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
46824 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
46827 getColumnRenderers : function(){
46828 var renderers = [];
46829 var cm = this.grid.colModel;
46830 var colCount = cm.getColumnCount();
46831 for(var i = 0; i < colCount; i++){
46832 renderers[i] = cm.getRenderer(i);
46837 getColumnIds : function(){
46839 var cm = this.grid.colModel;
46840 var colCount = cm.getColumnCount();
46841 for(var i = 0; i < colCount; i++){
46842 ids[i] = cm.getColumnId(i);
46847 getDataIndexes : function(){
46848 if(!this.indexMap){
46849 this.indexMap = this.buildIndexMap();
46851 return this.indexMap.colToData;
46854 getColumnIndexByDataIndex : function(dataIndex){
46855 if(!this.indexMap){
46856 this.indexMap = this.buildIndexMap();
46858 return this.indexMap.dataToCol[dataIndex];
46862 * Set a css style for a column dynamically.
46863 * @param {Number} colIndex The index of the column
46864 * @param {String} name The css property name
46865 * @param {String} value The css value
46867 setCSSStyle : function(colIndex, name, value){
46868 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
46869 Roo.util.CSS.updateRule(selector, name, value);
46872 generateRules : function(cm){
46873 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
46874 Roo.util.CSS.removeStyleSheet(rulesId);
46875 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46876 var cid = cm.getColumnId(i);
46877 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
46878 this.tdSelector, cid, " {\n}\n",
46879 this.hdSelector, cid, " {\n}\n",
46880 this.splitSelector, cid, " {\n}\n");
46882 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46886 * Ext JS Library 1.1.1
46887 * Copyright(c) 2006-2007, Ext JS, LLC.
46889 * Originally Released Under LGPL - original licence link has changed is not relivant.
46892 * <script type="text/javascript">
46896 // This is a support class used internally by the Grid components
46897 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
46899 this.view = grid.getView();
46900 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46901 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
46903 this.setHandleElId(Roo.id(hd));
46904 this.setOuterHandleElId(Roo.id(hd2));
46906 this.scroll = false;
46908 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
46910 getDragData : function(e){
46911 var t = Roo.lib.Event.getTarget(e);
46912 var h = this.view.findHeaderCell(t);
46914 return {ddel: h.firstChild, header:h};
46919 onInitDrag : function(e){
46920 this.view.headersDisabled = true;
46921 var clone = this.dragData.ddel.cloneNode(true);
46922 clone.id = Roo.id();
46923 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
46924 this.proxy.update(clone);
46928 afterValidDrop : function(){
46930 setTimeout(function(){
46931 v.headersDisabled = false;
46935 afterInvalidDrop : function(){
46937 setTimeout(function(){
46938 v.headersDisabled = false;
46944 * Ext JS Library 1.1.1
46945 * Copyright(c) 2006-2007, Ext JS, LLC.
46947 * Originally Released Under LGPL - original licence link has changed is not relivant.
46950 * <script type="text/javascript">
46953 // This is a support class used internally by the Grid components
46954 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
46956 this.view = grid.getView();
46957 // split the proxies so they don't interfere with mouse events
46958 this.proxyTop = Roo.DomHelper.append(document.body, {
46959 cls:"col-move-top", html:" "
46961 this.proxyBottom = Roo.DomHelper.append(document.body, {
46962 cls:"col-move-bottom", html:" "
46964 this.proxyTop.hide = this.proxyBottom.hide = function(){
46965 this.setLeftTop(-100,-100);
46966 this.setStyle("visibility", "hidden");
46968 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46969 // temporarily disabled
46970 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
46971 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
46973 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
46974 proxyOffsets : [-4, -9],
46975 fly: Roo.Element.fly,
46977 getTargetFromEvent : function(e){
46978 var t = Roo.lib.Event.getTarget(e);
46979 var cindex = this.view.findCellIndex(t);
46980 if(cindex !== false){
46981 return this.view.getHeaderCell(cindex);
46985 nextVisible : function(h){
46986 var v = this.view, cm = this.grid.colModel;
46989 if(!cm.isHidden(v.getCellIndex(h))){
46997 prevVisible : function(h){
46998 var v = this.view, cm = this.grid.colModel;
47001 if(!cm.isHidden(v.getCellIndex(h))){
47009 positionIndicator : function(h, n, e){
47010 var x = Roo.lib.Event.getPageX(e);
47011 var r = Roo.lib.Dom.getRegion(n.firstChild);
47012 var px, pt, py = r.top + this.proxyOffsets[1];
47013 if((r.right - x) <= (r.right-r.left)/2){
47014 px = r.right+this.view.borderWidth;
47020 var oldIndex = this.view.getCellIndex(h);
47021 var newIndex = this.view.getCellIndex(n);
47023 if(this.grid.colModel.isFixed(newIndex)){
47027 var locked = this.grid.colModel.isLocked(newIndex);
47032 if(oldIndex < newIndex){
47035 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47038 px += this.proxyOffsets[0];
47039 this.proxyTop.setLeftTop(px, py);
47040 this.proxyTop.show();
47041 if(!this.bottomOffset){
47042 this.bottomOffset = this.view.mainHd.getHeight();
47044 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47045 this.proxyBottom.show();
47049 onNodeEnter : function(n, dd, e, data){
47050 if(data.header != n){
47051 this.positionIndicator(data.header, n, e);
47055 onNodeOver : function(n, dd, e, data){
47056 var result = false;
47057 if(data.header != n){
47058 result = this.positionIndicator(data.header, n, e);
47061 this.proxyTop.hide();
47062 this.proxyBottom.hide();
47064 return result ? this.dropAllowed : this.dropNotAllowed;
47067 onNodeOut : function(n, dd, e, data){
47068 this.proxyTop.hide();
47069 this.proxyBottom.hide();
47072 onNodeDrop : function(n, dd, e, data){
47073 var h = data.header;
47075 var cm = this.grid.colModel;
47076 var x = Roo.lib.Event.getPageX(e);
47077 var r = Roo.lib.Dom.getRegion(n.firstChild);
47078 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47079 var oldIndex = this.view.getCellIndex(h);
47080 var newIndex = this.view.getCellIndex(n);
47081 var locked = cm.isLocked(newIndex);
47085 if(oldIndex < newIndex){
47088 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47091 cm.setLocked(oldIndex, locked, true);
47092 cm.moveColumn(oldIndex, newIndex);
47093 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47101 * Ext JS Library 1.1.1
47102 * Copyright(c) 2006-2007, Ext JS, LLC.
47104 * Originally Released Under LGPL - original licence link has changed is not relivant.
47107 * <script type="text/javascript">
47111 * @class Roo.grid.GridView
47112 * @extends Roo.util.Observable
47115 * @param {Object} config
47117 Roo.grid.GridView = function(config){
47118 Roo.grid.GridView.superclass.constructor.call(this);
47121 Roo.apply(this, config);
47124 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47127 * Override this function to apply custom css classes to rows during rendering
47128 * @param {Record} record The record
47129 * @param {Number} index
47130 * @method getRowClass
47132 rowClass : "x-grid-row",
47134 cellClass : "x-grid-col",
47136 tdClass : "x-grid-td",
47138 hdClass : "x-grid-hd",
47140 splitClass : "x-grid-split",
47142 sortClasses : ["sort-asc", "sort-desc"],
47144 enableMoveAnim : false,
47148 dh : Roo.DomHelper,
47150 fly : Roo.Element.fly,
47152 css : Roo.util.CSS,
47158 scrollIncrement : 22,
47160 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47162 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47164 bind : function(ds, cm){
47166 this.ds.un("load", this.onLoad, this);
47167 this.ds.un("datachanged", this.onDataChange, this);
47168 this.ds.un("add", this.onAdd, this);
47169 this.ds.un("remove", this.onRemove, this);
47170 this.ds.un("update", this.onUpdate, this);
47171 this.ds.un("clear", this.onClear, this);
47174 ds.on("load", this.onLoad, this);
47175 ds.on("datachanged", this.onDataChange, this);
47176 ds.on("add", this.onAdd, this);
47177 ds.on("remove", this.onRemove, this);
47178 ds.on("update", this.onUpdate, this);
47179 ds.on("clear", this.onClear, this);
47184 this.cm.un("widthchange", this.onColWidthChange, this);
47185 this.cm.un("headerchange", this.onHeaderChange, this);
47186 this.cm.un("hiddenchange", this.onHiddenChange, this);
47187 this.cm.un("columnmoved", this.onColumnMove, this);
47188 this.cm.un("columnlockchange", this.onColumnLock, this);
47191 this.generateRules(cm);
47192 cm.on("widthchange", this.onColWidthChange, this);
47193 cm.on("headerchange", this.onHeaderChange, this);
47194 cm.on("hiddenchange", this.onHiddenChange, this);
47195 cm.on("columnmoved", this.onColumnMove, this);
47196 cm.on("columnlockchange", this.onColumnLock, this);
47201 init: function(grid){
47202 Roo.grid.GridView.superclass.init.call(this, grid);
47204 this.bind(grid.dataSource, grid.colModel);
47206 grid.on("headerclick", this.handleHeaderClick, this);
47208 if(grid.trackMouseOver){
47209 grid.on("mouseover", this.onRowOver, this);
47210 grid.on("mouseout", this.onRowOut, this);
47212 grid.cancelTextSelection = function(){};
47213 this.gridId = grid.id;
47215 var tpls = this.templates || {};
47218 tpls.master = new Roo.Template(
47219 '<div class="x-grid" hidefocus="true">',
47220 '<div class="x-grid-topbar"></div>',
47221 '<div class="x-grid-scroller"><div></div></div>',
47222 '<div class="x-grid-locked">',
47223 '<div class="x-grid-header">{lockedHeader}</div>',
47224 '<div class="x-grid-body">{lockedBody}</div>',
47226 '<div class="x-grid-viewport">',
47227 '<div class="x-grid-header">{header}</div>',
47228 '<div class="x-grid-body">{body}</div>',
47230 '<div class="x-grid-bottombar"></div>',
47231 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47232 '<div class="x-grid-resize-proxy"> </div>',
47235 tpls.master.disableformats = true;
47239 tpls.header = new Roo.Template(
47240 '<table border="0" cellspacing="0" cellpadding="0">',
47241 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47244 tpls.header.disableformats = true;
47246 tpls.header.compile();
47249 tpls.hcell = new Roo.Template(
47250 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47251 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47254 tpls.hcell.disableFormats = true;
47256 tpls.hcell.compile();
47259 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47260 tpls.hsplit.disableFormats = true;
47262 tpls.hsplit.compile();
47265 tpls.body = new Roo.Template(
47266 '<table border="0" cellspacing="0" cellpadding="0">',
47267 "<tbody>{rows}</tbody>",
47270 tpls.body.disableFormats = true;
47272 tpls.body.compile();
47275 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47276 tpls.row.disableFormats = true;
47278 tpls.row.compile();
47281 tpls.cell = new Roo.Template(
47282 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47283 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47286 tpls.cell.disableFormats = true;
47288 tpls.cell.compile();
47290 this.templates = tpls;
47293 // remap these for backwards compat
47294 onColWidthChange : function(){
47295 this.updateColumns.apply(this, arguments);
47297 onHeaderChange : function(){
47298 this.updateHeaders.apply(this, arguments);
47300 onHiddenChange : function(){
47301 this.handleHiddenChange.apply(this, arguments);
47303 onColumnMove : function(){
47304 this.handleColumnMove.apply(this, arguments);
47306 onColumnLock : function(){
47307 this.handleLockChange.apply(this, arguments);
47310 onDataChange : function(){
47312 this.updateHeaderSortState();
47315 onClear : function(){
47319 onUpdate : function(ds, record){
47320 this.refreshRow(record);
47323 refreshRow : function(record){
47324 var ds = this.ds, index;
47325 if(typeof record == 'number'){
47327 record = ds.getAt(index);
47329 index = ds.indexOf(record);
47331 this.insertRows(ds, index, index, true);
47332 this.onRemove(ds, record, index+1, true);
47333 this.syncRowHeights(index, index);
47335 this.fireEvent("rowupdated", this, index, record);
47338 onAdd : function(ds, records, index){
47339 this.insertRows(ds, index, index + (records.length-1));
47342 onRemove : function(ds, record, index, isUpdate){
47343 if(isUpdate !== true){
47344 this.fireEvent("beforerowremoved", this, index, record);
47346 var bt = this.getBodyTable(), lt = this.getLockedTable();
47347 if(bt.rows[index]){
47348 bt.firstChild.removeChild(bt.rows[index]);
47350 if(lt.rows[index]){
47351 lt.firstChild.removeChild(lt.rows[index]);
47353 if(isUpdate !== true){
47354 this.stripeRows(index);
47355 this.syncRowHeights(index, index);
47357 this.fireEvent("rowremoved", this, index, record);
47361 onLoad : function(){
47362 this.scrollToTop();
47366 * Scrolls the grid to the top
47368 scrollToTop : function(){
47370 this.scroller.dom.scrollTop = 0;
47376 * Gets a panel in the header of the grid that can be used for toolbars etc.
47377 * After modifying the contents of this panel a call to grid.autoSize() may be
47378 * required to register any changes in size.
47379 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47380 * @return Roo.Element
47382 getHeaderPanel : function(doShow){
47384 this.headerPanel.show();
47386 return this.headerPanel;
47390 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47391 * After modifying the contents of this panel a call to grid.autoSize() may be
47392 * required to register any changes in size.
47393 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47394 * @return Roo.Element
47396 getFooterPanel : function(doShow){
47398 this.footerPanel.show();
47400 return this.footerPanel;
47403 initElements : function(){
47404 var E = Roo.Element;
47405 var el = this.grid.getGridEl().dom.firstChild;
47406 var cs = el.childNodes;
47408 this.el = new E(el);
47409 this.headerPanel = new E(el.firstChild);
47410 this.headerPanel.enableDisplayMode("block");
47412 this.scroller = new E(cs[1]);
47413 this.scrollSizer = new E(this.scroller.dom.firstChild);
47415 this.lockedWrap = new E(cs[2]);
47416 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47417 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47419 this.mainWrap = new E(cs[3]);
47420 this.mainHd = new E(this.mainWrap.dom.firstChild);
47421 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47423 this.footerPanel = new E(cs[4]);
47424 this.footerPanel.enableDisplayMode("block");
47426 this.focusEl = new E(cs[5]);
47427 this.focusEl.swallowEvent("click", true);
47428 this.resizeProxy = new E(cs[6]);
47430 this.headerSelector = String.format(
47431 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47432 this.lockedHd.id, this.mainHd.id
47435 this.splitterSelector = String.format(
47436 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47437 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47440 idToCssName : function(s)
47442 return s.replace(/[^a-z0-9]+/ig, '-');
47445 getHeaderCell : function(index){
47446 return Roo.DomQuery.select(this.headerSelector)[index];
47449 getHeaderCellMeasure : function(index){
47450 return this.getHeaderCell(index).firstChild;
47453 getHeaderCellText : function(index){
47454 return this.getHeaderCell(index).firstChild.firstChild;
47457 getLockedTable : function(){
47458 return this.lockedBody.dom.firstChild;
47461 getBodyTable : function(){
47462 return this.mainBody.dom.firstChild;
47465 getLockedRow : function(index){
47466 return this.getLockedTable().rows[index];
47469 getRow : function(index){
47470 return this.getBodyTable().rows[index];
47473 getRowComposite : function(index){
47475 this.rowEl = new Roo.CompositeElementLite();
47477 var els = [], lrow, mrow;
47478 if(lrow = this.getLockedRow(index)){
47481 if(mrow = this.getRow(index)){
47484 this.rowEl.elements = els;
47488 getCell : function(rowIndex, colIndex){
47489 var locked = this.cm.getLockedCount();
47491 if(colIndex < locked){
47492 source = this.lockedBody.dom.firstChild;
47494 source = this.mainBody.dom.firstChild;
47495 colIndex -= locked;
47497 return source.rows[rowIndex].childNodes[colIndex];
47500 getCellText : function(rowIndex, colIndex){
47501 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47504 getCellBox : function(cell){
47505 var b = this.fly(cell).getBox();
47506 if(Roo.isOpera){ // opera fails to report the Y
47507 b.y = cell.offsetTop + this.mainBody.getY();
47512 getCellIndex : function(cell){
47513 var id = String(cell.className).match(this.cellRE);
47515 return parseInt(id[1], 10);
47520 findHeaderIndex : function(n){
47521 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47522 return r ? this.getCellIndex(r) : false;
47525 findHeaderCell : function(n){
47526 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47527 return r ? r : false;
47530 findRowIndex : function(n){
47534 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47535 return r ? r.rowIndex : false;
47538 findCellIndex : function(node){
47539 var stop = this.el.dom;
47540 while(node && node != stop){
47541 if(this.findRE.test(node.className)){
47542 return this.getCellIndex(node);
47544 node = node.parentNode;
47549 getColumnId : function(index){
47550 return this.cm.getColumnId(index);
47553 getSplitters : function(){
47554 if(this.splitterSelector){
47555 return Roo.DomQuery.select(this.splitterSelector);
47561 getSplitter : function(index){
47562 return this.getSplitters()[index];
47565 onRowOver : function(e, t){
47567 if((row = this.findRowIndex(t)) !== false){
47568 this.getRowComposite(row).addClass("x-grid-row-over");
47572 onRowOut : function(e, t){
47574 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47575 this.getRowComposite(row).removeClass("x-grid-row-over");
47579 renderHeaders : function(){
47581 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47582 var cb = [], lb = [], sb = [], lsb = [], p = {};
47583 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47584 p.cellId = "x-grid-hd-0-" + i;
47585 p.splitId = "x-grid-csplit-0-" + i;
47586 p.id = cm.getColumnId(i);
47587 p.title = cm.getColumnTooltip(i) || "";
47588 p.value = cm.getColumnHeader(i) || "";
47589 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47590 if(!cm.isLocked(i)){
47591 cb[cb.length] = ct.apply(p);
47592 sb[sb.length] = st.apply(p);
47594 lb[lb.length] = ct.apply(p);
47595 lsb[lsb.length] = st.apply(p);
47598 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47599 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47602 updateHeaders : function(){
47603 var html = this.renderHeaders();
47604 this.lockedHd.update(html[0]);
47605 this.mainHd.update(html[1]);
47609 * Focuses the specified row.
47610 * @param {Number} row The row index
47612 focusRow : function(row){
47613 var x = this.scroller.dom.scrollLeft;
47614 this.focusCell(row, 0, false);
47615 this.scroller.dom.scrollLeft = x;
47619 * Focuses the specified cell.
47620 * @param {Number} row The row index
47621 * @param {Number} col The column index
47622 * @param {Boolean} hscroll false to disable horizontal scrolling
47624 focusCell : function(row, col, hscroll){
47625 var el = this.ensureVisible(row, col, hscroll);
47626 this.focusEl.alignTo(el, "tl-tl");
47628 this.focusEl.focus();
47630 this.focusEl.focus.defer(1, this.focusEl);
47635 * Scrolls the specified cell into view
47636 * @param {Number} row The row index
47637 * @param {Number} col The column index
47638 * @param {Boolean} hscroll false to disable horizontal scrolling
47640 ensureVisible : function(row, col, hscroll){
47641 if(typeof row != "number"){
47642 row = row.rowIndex;
47644 if(row < 0 && row >= this.ds.getCount()){
47647 col = (col !== undefined ? col : 0);
47648 var cm = this.grid.colModel;
47649 while(cm.isHidden(col)){
47653 var el = this.getCell(row, col);
47657 var c = this.scroller.dom;
47659 var ctop = parseInt(el.offsetTop, 10);
47660 var cleft = parseInt(el.offsetLeft, 10);
47661 var cbot = ctop + el.offsetHeight;
47662 var cright = cleft + el.offsetWidth;
47664 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47665 var stop = parseInt(c.scrollTop, 10);
47666 var sleft = parseInt(c.scrollLeft, 10);
47667 var sbot = stop + ch;
47668 var sright = sleft + c.clientWidth;
47671 c.scrollTop = ctop;
47672 }else if(cbot > sbot){
47673 c.scrollTop = cbot-ch;
47676 if(hscroll !== false){
47678 c.scrollLeft = cleft;
47679 }else if(cright > sright){
47680 c.scrollLeft = cright-c.clientWidth;
47686 updateColumns : function(){
47687 this.grid.stopEditing();
47688 var cm = this.grid.colModel, colIds = this.getColumnIds();
47689 //var totalWidth = cm.getTotalWidth();
47691 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47692 //if(cm.isHidden(i)) continue;
47693 var w = cm.getColumnWidth(i);
47694 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47695 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47697 this.updateSplitters();
47700 generateRules : function(cm){
47701 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
47702 Roo.util.CSS.removeStyleSheet(rulesId);
47703 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47704 var cid = cm.getColumnId(i);
47706 if(cm.config[i].align){
47707 align = 'text-align:'+cm.config[i].align+';';
47710 if(cm.isHidden(i)){
47711 hidden = 'display:none;';
47713 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
47715 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
47716 this.hdSelector, cid, " {\n", align, width, "}\n",
47717 this.tdSelector, cid, " {\n",hidden,"\n}\n",
47718 this.splitSelector, cid, " {\n", hidden , "\n}\n");
47720 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47723 updateSplitters : function(){
47724 var cm = this.cm, s = this.getSplitters();
47725 if(s){ // splitters not created yet
47726 var pos = 0, locked = true;
47727 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47728 if(cm.isHidden(i)) continue;
47729 var w = cm.getColumnWidth(i);
47730 if(!cm.isLocked(i) && locked){
47735 s[i].style.left = (pos-this.splitOffset) + "px";
47740 handleHiddenChange : function(colModel, colIndex, hidden){
47742 this.hideColumn(colIndex);
47744 this.unhideColumn(colIndex);
47748 hideColumn : function(colIndex){
47749 var cid = this.getColumnId(colIndex);
47750 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
47751 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
47753 this.updateHeaders();
47755 this.updateSplitters();
47759 unhideColumn : function(colIndex){
47760 var cid = this.getColumnId(colIndex);
47761 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
47762 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
47765 this.updateHeaders();
47767 this.updateSplitters();
47771 insertRows : function(dm, firstRow, lastRow, isUpdate){
47772 if(firstRow == 0 && lastRow == dm.getCount()-1){
47776 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
47778 var s = this.getScrollState();
47779 var markup = this.renderRows(firstRow, lastRow);
47780 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
47781 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
47782 this.restoreScroll(s);
47784 this.fireEvent("rowsinserted", this, firstRow, lastRow);
47785 this.syncRowHeights(firstRow, lastRow);
47786 this.stripeRows(firstRow);
47792 bufferRows : function(markup, target, index){
47793 var before = null, trows = target.rows, tbody = target.tBodies[0];
47794 if(index < trows.length){
47795 before = trows[index];
47797 var b = document.createElement("div");
47798 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
47799 var rows = b.firstChild.rows;
47800 for(var i = 0, len = rows.length; i < len; i++){
47802 tbody.insertBefore(rows[0], before);
47804 tbody.appendChild(rows[0]);
47811 deleteRows : function(dm, firstRow, lastRow){
47812 if(dm.getRowCount()<1){
47813 this.fireEvent("beforerefresh", this);
47814 this.mainBody.update("");
47815 this.lockedBody.update("");
47816 this.fireEvent("refresh", this);
47818 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
47819 var bt = this.getBodyTable();
47820 var tbody = bt.firstChild;
47821 var rows = bt.rows;
47822 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
47823 tbody.removeChild(rows[firstRow]);
47825 this.stripeRows(firstRow);
47826 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
47830 updateRows : function(dataSource, firstRow, lastRow){
47831 var s = this.getScrollState();
47833 this.restoreScroll(s);
47836 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
47840 this.updateHeaderSortState();
47843 getScrollState : function(){
47844 var sb = this.scroller.dom;
47845 return {left: sb.scrollLeft, top: sb.scrollTop};
47848 stripeRows : function(startRow){
47849 if(!this.grid.stripeRows || this.ds.getCount() < 1){
47852 startRow = startRow || 0;
47853 var rows = this.getBodyTable().rows;
47854 var lrows = this.getLockedTable().rows;
47855 var cls = ' x-grid-row-alt ';
47856 for(var i = startRow, len = rows.length; i < len; i++){
47857 var row = rows[i], lrow = lrows[i];
47858 var isAlt = ((i+1) % 2 == 0);
47859 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
47860 if(isAlt == hasAlt){
47864 row.className += " x-grid-row-alt";
47866 row.className = row.className.replace("x-grid-row-alt", "");
47869 lrow.className = row.className;
47874 restoreScroll : function(state){
47875 var sb = this.scroller.dom;
47876 sb.scrollLeft = state.left;
47877 sb.scrollTop = state.top;
47881 syncScroll : function(){
47882 var sb = this.scroller.dom;
47883 var sh = this.mainHd.dom;
47884 var bs = this.mainBody.dom;
47885 var lv = this.lockedBody.dom;
47886 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
47887 lv.scrollTop = bs.scrollTop = sb.scrollTop;
47890 handleScroll : function(e){
47892 var sb = this.scroller.dom;
47893 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
47897 handleWheel : function(e){
47898 var d = e.getWheelDelta();
47899 this.scroller.dom.scrollTop -= d*22;
47900 // set this here to prevent jumpy scrolling on large tables
47901 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
47905 renderRows : function(startRow, endRow){
47906 // pull in all the crap needed to render rows
47907 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
47908 var colCount = cm.getColumnCount();
47910 if(ds.getCount() < 1){
47914 // build a map for all the columns
47916 for(var i = 0; i < colCount; i++){
47917 var name = cm.getDataIndex(i);
47919 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
47920 renderer : cm.getRenderer(i),
47921 id : cm.getColumnId(i),
47922 locked : cm.isLocked(i)
47926 startRow = startRow || 0;
47927 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
47929 // records to render
47930 var rs = ds.getRange(startRow, endRow);
47932 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
47935 // As much as I hate to duplicate code, this was branched because FireFox really hates
47936 // [].join("") on strings. The performance difference was substantial enough to
47937 // branch this function
47938 doRender : Roo.isGecko ?
47939 function(cs, rs, ds, startRow, colCount, stripe){
47940 var ts = this.templates, ct = ts.cell, rt = ts.row;
47942 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47943 for(var j = 0, len = rs.length; j < len; j++){
47944 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
47945 for(var i = 0; i < colCount; i++){
47947 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47949 p.css = p.attr = "";
47950 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47951 if(p.value == undefined || p.value === "") p.value = " ";
47952 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47953 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47955 var markup = ct.apply(p);
47963 if(stripe && ((rowIndex+1) % 2 == 0)){
47964 alt[0] = "x-grid-row-alt";
47967 alt[1] = " x-grid-dirty-row";
47970 if(this.getRowClass){
47971 alt[2] = this.getRowClass(r, rowIndex);
47973 rp.alt = alt.join(" ");
47974 lbuf+= rt.apply(rp);
47976 buf+= rt.apply(rp);
47978 return [lbuf, buf];
47980 function(cs, rs, ds, startRow, colCount, stripe){
47981 var ts = this.templates, ct = ts.cell, rt = ts.row;
47983 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47984 for(var j = 0, len = rs.length; j < len; j++){
47985 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
47986 for(var i = 0; i < colCount; i++){
47988 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47990 p.css = p.attr = "";
47991 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47992 if(p.value == undefined || p.value === "") p.value = " ";
47993 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47994 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47996 var markup = ct.apply(p);
47998 cb[cb.length] = markup;
48000 lcb[lcb.length] = markup;
48004 if(stripe && ((rowIndex+1) % 2 == 0)){
48005 alt[0] = "x-grid-row-alt";
48008 alt[1] = " x-grid-dirty-row";
48011 if(this.getRowClass){
48012 alt[2] = this.getRowClass(r, rowIndex);
48014 rp.alt = alt.join(" ");
48015 rp.cells = lcb.join("");
48016 lbuf[lbuf.length] = rt.apply(rp);
48017 rp.cells = cb.join("");
48018 buf[buf.length] = rt.apply(rp);
48020 return [lbuf.join(""), buf.join("")];
48023 renderBody : function(){
48024 var markup = this.renderRows();
48025 var bt = this.templates.body;
48026 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48030 * Refreshes the grid
48031 * @param {Boolean} headersToo
48033 refresh : function(headersToo){
48034 this.fireEvent("beforerefresh", this);
48035 this.grid.stopEditing();
48036 var result = this.renderBody();
48037 this.lockedBody.update(result[0]);
48038 this.mainBody.update(result[1]);
48039 if(headersToo === true){
48040 this.updateHeaders();
48041 this.updateColumns();
48042 this.updateSplitters();
48043 this.updateHeaderSortState();
48045 this.syncRowHeights();
48047 this.fireEvent("refresh", this);
48050 handleColumnMove : function(cm, oldIndex, newIndex){
48051 this.indexMap = null;
48052 var s = this.getScrollState();
48053 this.refresh(true);
48054 this.restoreScroll(s);
48055 this.afterMove(newIndex);
48058 afterMove : function(colIndex){
48059 if(this.enableMoveAnim && Roo.enableFx){
48060 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48064 updateCell : function(dm, rowIndex, dataIndex){
48065 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48066 if(typeof colIndex == "undefined"){ // not present in grid
48069 var cm = this.grid.colModel;
48070 var cell = this.getCell(rowIndex, colIndex);
48071 var cellText = this.getCellText(rowIndex, colIndex);
48074 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48075 id : cm.getColumnId(colIndex),
48076 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48078 var renderer = cm.getRenderer(colIndex);
48079 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48080 if(typeof val == "undefined" || val === "") val = " ";
48081 cellText.innerHTML = val;
48082 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48083 this.syncRowHeights(rowIndex, rowIndex);
48086 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48088 if(this.grid.autoSizeHeaders){
48089 var h = this.getHeaderCellMeasure(colIndex);
48090 maxWidth = Math.max(maxWidth, h.scrollWidth);
48093 if(this.cm.isLocked(colIndex)){
48094 tb = this.getLockedTable();
48097 tb = this.getBodyTable();
48098 index = colIndex - this.cm.getLockedCount();
48101 var rows = tb.rows;
48102 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48103 for(var i = 0; i < stopIndex; i++){
48104 var cell = rows[i].childNodes[index].firstChild;
48105 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48108 return maxWidth + /*margin for error in IE*/ 5;
48111 * Autofit a column to its content.
48112 * @param {Number} colIndex
48113 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48115 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48116 if(this.cm.isHidden(colIndex)){
48117 return; // can't calc a hidden column
48120 var cid = this.cm.getColumnId(colIndex);
48121 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48122 if(this.grid.autoSizeHeaders){
48123 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48126 var newWidth = this.calcColumnWidth(colIndex);
48127 this.cm.setColumnWidth(colIndex,
48128 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48129 if(!suppressEvent){
48130 this.grid.fireEvent("columnresize", colIndex, newWidth);
48135 * Autofits all columns to their content and then expands to fit any extra space in the grid
48137 autoSizeColumns : function(){
48138 var cm = this.grid.colModel;
48139 var colCount = cm.getColumnCount();
48140 for(var i = 0; i < colCount; i++){
48141 this.autoSizeColumn(i, true, true);
48143 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48146 this.updateColumns();
48152 * Autofits all columns to the grid's width proportionate with their current size
48153 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48155 fitColumns : function(reserveScrollSpace){
48156 var cm = this.grid.colModel;
48157 var colCount = cm.getColumnCount();
48161 for (i = 0; i < colCount; i++){
48162 if(!cm.isHidden(i) && !cm.isFixed(i)){
48163 w = cm.getColumnWidth(i);
48169 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48170 if(reserveScrollSpace){
48173 var frac = (avail - cm.getTotalWidth())/width;
48174 while (cols.length){
48177 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48179 this.updateColumns();
48183 onRowSelect : function(rowIndex){
48184 var row = this.getRowComposite(rowIndex);
48185 row.addClass("x-grid-row-selected");
48188 onRowDeselect : function(rowIndex){
48189 var row = this.getRowComposite(rowIndex);
48190 row.removeClass("x-grid-row-selected");
48193 onCellSelect : function(row, col){
48194 var cell = this.getCell(row, col);
48196 Roo.fly(cell).addClass("x-grid-cell-selected");
48200 onCellDeselect : function(row, col){
48201 var cell = this.getCell(row, col);
48203 Roo.fly(cell).removeClass("x-grid-cell-selected");
48207 updateHeaderSortState : function(){
48208 var state = this.ds.getSortState();
48212 this.sortState = state;
48213 var sortColumn = this.cm.findColumnIndex(state.field);
48214 if(sortColumn != -1){
48215 var sortDir = state.direction;
48216 var sc = this.sortClasses;
48217 var hds = this.el.select(this.headerSelector).removeClass(sc);
48218 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48222 handleHeaderClick : function(g, index){
48223 if(this.headersDisabled){
48226 var dm = g.dataSource, cm = g.colModel;
48227 if(!cm.isSortable(index)){
48231 dm.sort(cm.getDataIndex(index));
48235 destroy : function(){
48237 this.colMenu.removeAll();
48238 Roo.menu.MenuMgr.unregister(this.colMenu);
48239 this.colMenu.getEl().remove();
48240 delete this.colMenu;
48243 this.hmenu.removeAll();
48244 Roo.menu.MenuMgr.unregister(this.hmenu);
48245 this.hmenu.getEl().remove();
48248 if(this.grid.enableColumnMove){
48249 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48251 for(var dd in dds){
48252 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48253 var elid = dds[dd].dragElId;
48255 Roo.get(elid).remove();
48256 } else if(dds[dd].config.isTarget){
48257 dds[dd].proxyTop.remove();
48258 dds[dd].proxyBottom.remove();
48261 if(Roo.dd.DDM.locationCache[dd]){
48262 delete Roo.dd.DDM.locationCache[dd];
48265 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48268 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48269 this.bind(null, null);
48270 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48273 handleLockChange : function(){
48274 this.refresh(true);
48277 onDenyColumnLock : function(){
48281 onDenyColumnHide : function(){
48285 handleHdMenuClick : function(item){
48286 var index = this.hdCtxIndex;
48287 var cm = this.cm, ds = this.ds;
48290 ds.sort(cm.getDataIndex(index), "ASC");
48293 ds.sort(cm.getDataIndex(index), "DESC");
48296 var lc = cm.getLockedCount();
48297 if(cm.getColumnCount(true) <= lc+1){
48298 this.onDenyColumnLock();
48302 cm.setLocked(index, true, true);
48303 cm.moveColumn(index, lc);
48304 this.grid.fireEvent("columnmove", index, lc);
48306 cm.setLocked(index, true);
48310 var lc = cm.getLockedCount();
48311 if((lc-1) != index){
48312 cm.setLocked(index, false, true);
48313 cm.moveColumn(index, lc-1);
48314 this.grid.fireEvent("columnmove", index, lc-1);
48316 cm.setLocked(index, false);
48320 index = cm.getIndexById(item.id.substr(4));
48322 if(item.checked && cm.getColumnCount(true) <= 1){
48323 this.onDenyColumnHide();
48326 cm.setHidden(index, item.checked);
48332 beforeColMenuShow : function(){
48333 var cm = this.cm, colCount = cm.getColumnCount();
48334 this.colMenu.removeAll();
48335 for(var i = 0; i < colCount; i++){
48336 this.colMenu.add(new Roo.menu.CheckItem({
48337 id: "col-"+cm.getColumnId(i),
48338 text: cm.getColumnHeader(i),
48339 checked: !cm.isHidden(i),
48345 handleHdCtx : function(g, index, e){
48347 var hd = this.getHeaderCell(index);
48348 this.hdCtxIndex = index;
48349 var ms = this.hmenu.items, cm = this.cm;
48350 ms.get("asc").setDisabled(!cm.isSortable(index));
48351 ms.get("desc").setDisabled(!cm.isSortable(index));
48352 if(this.grid.enableColLock !== false){
48353 ms.get("lock").setDisabled(cm.isLocked(index));
48354 ms.get("unlock").setDisabled(!cm.isLocked(index));
48356 this.hmenu.show(hd, "tl-bl");
48359 handleHdOver : function(e){
48360 var hd = this.findHeaderCell(e.getTarget());
48361 if(hd && !this.headersDisabled){
48362 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48363 this.fly(hd).addClass("x-grid-hd-over");
48368 handleHdOut : function(e){
48369 var hd = this.findHeaderCell(e.getTarget());
48371 this.fly(hd).removeClass("x-grid-hd-over");
48375 handleSplitDblClick : function(e, t){
48376 var i = this.getCellIndex(t);
48377 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48378 this.autoSizeColumn(i, true);
48383 render : function(){
48386 var colCount = cm.getColumnCount();
48388 if(this.grid.monitorWindowResize === true){
48389 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48391 var header = this.renderHeaders();
48392 var body = this.templates.body.apply({rows:""});
48393 var html = this.templates.master.apply({
48396 lockedHeader: header[0],
48400 //this.updateColumns();
48402 this.grid.getGridEl().dom.innerHTML = html;
48404 this.initElements();
48406 // a kludge to fix the random scolling effect in webkit
48407 this.el.on("scroll", function() {
48408 this.el.dom.scrollTop=0; // hopefully not recursive..
48411 this.scroller.on("scroll", this.handleScroll, this);
48412 this.lockedBody.on("mousewheel", this.handleWheel, this);
48413 this.mainBody.on("mousewheel", this.handleWheel, this);
48415 this.mainHd.on("mouseover", this.handleHdOver, this);
48416 this.mainHd.on("mouseout", this.handleHdOut, this);
48417 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48418 {delegate: "."+this.splitClass});
48420 this.lockedHd.on("mouseover", this.handleHdOver, this);
48421 this.lockedHd.on("mouseout", this.handleHdOut, this);
48422 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48423 {delegate: "."+this.splitClass});
48425 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48426 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48429 this.updateSplitters();
48431 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48432 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48433 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48436 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48437 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48439 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48440 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48442 if(this.grid.enableColLock !== false){
48443 this.hmenu.add('-',
48444 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48445 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48448 if(this.grid.enableColumnHide !== false){
48450 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48451 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48452 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48454 this.hmenu.add('-',
48455 {id:"columns", text: this.columnsText, menu: this.colMenu}
48458 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48460 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48463 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48464 this.dd = new Roo.grid.GridDragZone(this.grid, {
48465 ddGroup : this.grid.ddGroup || 'GridDD'
48470 for(var i = 0; i < colCount; i++){
48471 if(cm.isHidden(i)){
48472 this.hideColumn(i);
48474 if(cm.config[i].align){
48475 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48476 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48480 this.updateHeaderSortState();
48482 this.beforeInitialResize();
48485 // two part rendering gives faster view to the user
48486 this.renderPhase2.defer(1, this);
48489 renderPhase2 : function(){
48490 // render the rows now
48492 if(this.grid.autoSizeColumns){
48493 this.autoSizeColumns();
48497 beforeInitialResize : function(){
48501 onColumnSplitterMoved : function(i, w){
48502 this.userResized = true;
48503 var cm = this.grid.colModel;
48504 cm.setColumnWidth(i, w, true);
48505 var cid = cm.getColumnId(i);
48506 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48507 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48508 this.updateSplitters();
48510 this.grid.fireEvent("columnresize", i, w);
48513 syncRowHeights : function(startIndex, endIndex){
48514 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48515 startIndex = startIndex || 0;
48516 var mrows = this.getBodyTable().rows;
48517 var lrows = this.getLockedTable().rows;
48518 var len = mrows.length-1;
48519 endIndex = Math.min(endIndex || len, len);
48520 for(var i = startIndex; i <= endIndex; i++){
48521 var m = mrows[i], l = lrows[i];
48522 var h = Math.max(m.offsetHeight, l.offsetHeight);
48523 m.style.height = l.style.height = h + "px";
48528 layout : function(initialRender, is2ndPass){
48530 var auto = g.autoHeight;
48531 var scrollOffset = 16;
48532 var c = g.getGridEl(), cm = this.cm,
48533 expandCol = g.autoExpandColumn,
48535 //c.beginMeasure();
48537 if(!c.dom.offsetWidth){ // display:none?
48539 this.lockedWrap.show();
48540 this.mainWrap.show();
48545 var hasLock = this.cm.isLocked(0);
48547 var tbh = this.headerPanel.getHeight();
48548 var bbh = this.footerPanel.getHeight();
48551 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
48552 var newHeight = ch + c.getBorderWidth("tb");
48554 newHeight = Math.min(g.maxHeight, newHeight);
48556 c.setHeight(newHeight);
48560 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48563 var s = this.scroller;
48565 var csize = c.getSize(true);
48567 this.el.setSize(csize.width, csize.height);
48569 this.headerPanel.setWidth(csize.width);
48570 this.footerPanel.setWidth(csize.width);
48572 var hdHeight = this.mainHd.getHeight();
48573 var vw = csize.width;
48574 var vh = csize.height - (tbh + bbh);
48578 var bt = this.getBodyTable();
48579 var ltWidth = hasLock ?
48580 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
48582 var scrollHeight = bt.offsetHeight;
48583 var scrollWidth = ltWidth + bt.offsetWidth;
48584 var vscroll = false, hscroll = false;
48586 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
48588 var lw = this.lockedWrap, mw = this.mainWrap;
48589 var lb = this.lockedBody, mb = this.mainBody;
48591 setTimeout(function(){
48592 var t = s.dom.offsetTop;
48593 var w = s.dom.clientWidth,
48594 h = s.dom.clientHeight;
48597 lw.setSize(ltWidth, h);
48599 mw.setLeftTop(ltWidth, t);
48600 mw.setSize(w-ltWidth, h);
48602 lb.setHeight(h-hdHeight);
48603 mb.setHeight(h-hdHeight);
48605 if(is2ndPass !== true && !gv.userResized && expandCol){
48606 // high speed resize without full column calculation
48608 var ci = cm.getIndexById(expandCol);
48610 ci = cm.findColumnIndex(expandCol);
48612 ci = Math.max(0, ci); // make sure it's got at least the first col.
48613 var expandId = cm.getColumnId(ci);
48614 var tw = cm.getTotalWidth(false);
48615 var currentWidth = cm.getColumnWidth(ci);
48616 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
48617 if(currentWidth != cw){
48618 cm.setColumnWidth(ci, cw, true);
48619 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48620 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48621 gv.updateSplitters();
48622 gv.layout(false, true);
48634 onWindowResize : function(){
48635 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
48641 appendFooter : function(parentEl){
48645 sortAscText : "Sort Ascending",
48646 sortDescText : "Sort Descending",
48647 lockText : "Lock Column",
48648 unlockText : "Unlock Column",
48649 columnsText : "Columns"
48653 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
48654 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
48655 this.proxy.el.addClass('x-grid3-col-dd');
48658 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
48659 handleMouseDown : function(e){
48663 callHandleMouseDown : function(e){
48664 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
48669 * Ext JS Library 1.1.1
48670 * Copyright(c) 2006-2007, Ext JS, LLC.
48672 * Originally Released Under LGPL - original licence link has changed is not relivant.
48675 * <script type="text/javascript">
48679 // This is a support class used internally by the Grid components
48680 Roo.grid.SplitDragZone = function(grid, hd, hd2){
48682 this.view = grid.getView();
48683 this.proxy = this.view.resizeProxy;
48684 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
48685 "gridSplitters" + this.grid.getGridEl().id, {
48686 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
48688 this.setHandleElId(Roo.id(hd));
48689 this.setOuterHandleElId(Roo.id(hd2));
48690 this.scroll = false;
48692 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
48693 fly: Roo.Element.fly,
48695 b4StartDrag : function(x, y){
48696 this.view.headersDisabled = true;
48697 this.proxy.setHeight(this.view.mainWrap.getHeight());
48698 var w = this.cm.getColumnWidth(this.cellIndex);
48699 var minw = Math.max(w-this.grid.minColumnWidth, 0);
48700 this.resetConstraints();
48701 this.setXConstraint(minw, 1000);
48702 this.setYConstraint(0, 0);
48703 this.minX = x - minw;
48704 this.maxX = x + 1000;
48706 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
48710 handleMouseDown : function(e){
48711 ev = Roo.EventObject.setEvent(e);
48712 var t = this.fly(ev.getTarget());
48713 if(t.hasClass("x-grid-split")){
48714 this.cellIndex = this.view.getCellIndex(t.dom);
48715 this.split = t.dom;
48716 this.cm = this.grid.colModel;
48717 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
48718 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
48723 endDrag : function(e){
48724 this.view.headersDisabled = false;
48725 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
48726 var diff = endX - this.startPos;
48727 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
48730 autoOffset : function(){
48731 this.setDelta(0,0);
48735 * Ext JS Library 1.1.1
48736 * Copyright(c) 2006-2007, Ext JS, LLC.
48738 * Originally Released Under LGPL - original licence link has changed is not relivant.
48741 * <script type="text/javascript">
48745 // This is a support class used internally by the Grid components
48746 Roo.grid.GridDragZone = function(grid, config){
48747 this.view = grid.getView();
48748 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
48749 if(this.view.lockedBody){
48750 this.setHandleElId(Roo.id(this.view.mainBody.dom));
48751 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
48753 this.scroll = false;
48755 this.ddel = document.createElement('div');
48756 this.ddel.className = 'x-grid-dd-wrap';
48759 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
48760 ddGroup : "GridDD",
48762 getDragData : function(e){
48763 var t = Roo.lib.Event.getTarget(e);
48764 var rowIndex = this.view.findRowIndex(t);
48765 if(rowIndex !== false){
48766 var sm = this.grid.selModel;
48767 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
48768 // sm.mouseDown(e, t);
48770 if (e.hasModifier()){
48771 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
48773 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
48778 onInitDrag : function(e){
48779 var data = this.dragData;
48780 this.ddel.innerHTML = this.grid.getDragDropText();
48781 this.proxy.update(this.ddel);
48782 // fire start drag?
48785 afterRepair : function(){
48786 this.dragging = false;
48789 getRepairXY : function(e, data){
48793 onEndDrag : function(data, e){
48797 onValidDrop : function(dd, e, id){
48802 beforeInvalidDrop : function(e, id){
48807 * Ext JS Library 1.1.1
48808 * Copyright(c) 2006-2007, Ext JS, LLC.
48810 * Originally Released Under LGPL - original licence link has changed is not relivant.
48813 * <script type="text/javascript">
48818 * @class Roo.grid.ColumnModel
48819 * @extends Roo.util.Observable
48820 * This is the default implementation of a ColumnModel used by the Grid. It defines
48821 * the columns in the grid.
48824 var colModel = new Roo.grid.ColumnModel([
48825 {header: "Ticker", width: 60, sortable: true, locked: true},
48826 {header: "Company Name", width: 150, sortable: true},
48827 {header: "Market Cap.", width: 100, sortable: true},
48828 {header: "$ Sales", width: 100, sortable: true, renderer: money},
48829 {header: "Employees", width: 100, sortable: true, resizable: false}
48834 * The config options listed for this class are options which may appear in each
48835 * individual column definition.
48836 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
48838 * @param {Object} config An Array of column config objects. See this class's
48839 * config objects for details.
48841 Roo.grid.ColumnModel = function(config){
48843 * The config passed into the constructor
48845 this.config = config;
48848 // if no id, create one
48849 // if the column does not have a dataIndex mapping,
48850 // map it to the order it is in the config
48851 for(var i = 0, len = config.length; i < len; i++){
48853 if(typeof c.dataIndex == "undefined"){
48856 if(typeof c.renderer == "string"){
48857 c.renderer = Roo.util.Format[c.renderer];
48859 if(typeof c.id == "undefined"){
48862 if(c.editor && c.editor.xtype){
48863 c.editor = Roo.factory(c.editor, Roo.grid);
48865 if(c.editor && c.editor.isFormField){
48866 c.editor = new Roo.grid.GridEditor(c.editor);
48868 this.lookup[c.id] = c;
48872 * The width of columns which have no width specified (defaults to 100)
48875 this.defaultWidth = 100;
48878 * Default sortable of columns which have no sortable specified (defaults to false)
48881 this.defaultSortable = false;
48885 * @event widthchange
48886 * Fires when the width of a column changes.
48887 * @param {ColumnModel} this
48888 * @param {Number} columnIndex The column index
48889 * @param {Number} newWidth The new width
48891 "widthchange": true,
48893 * @event headerchange
48894 * Fires when the text of a header changes.
48895 * @param {ColumnModel} this
48896 * @param {Number} columnIndex The column index
48897 * @param {Number} newText The new header text
48899 "headerchange": true,
48901 * @event hiddenchange
48902 * Fires when a column is hidden or "unhidden".
48903 * @param {ColumnModel} this
48904 * @param {Number} columnIndex The column index
48905 * @param {Boolean} hidden true if hidden, false otherwise
48907 "hiddenchange": true,
48909 * @event columnmoved
48910 * Fires when a column is moved.
48911 * @param {ColumnModel} this
48912 * @param {Number} oldIndex
48913 * @param {Number} newIndex
48915 "columnmoved" : true,
48917 * @event columlockchange
48918 * Fires when a column's locked state is changed
48919 * @param {ColumnModel} this
48920 * @param {Number} colIndex
48921 * @param {Boolean} locked true if locked
48923 "columnlockchange" : true
48925 Roo.grid.ColumnModel.superclass.constructor.call(this);
48927 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
48929 * @cfg {String} header The header text to display in the Grid view.
48932 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
48933 * {@link Roo.data.Record} definition from which to draw the column's value. If not
48934 * specified, the column's index is used as an index into the Record's data Array.
48937 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
48938 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
48941 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
48942 * Defaults to the value of the {@link #defaultSortable} property.
48943 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
48946 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
48949 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
48952 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
48955 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
48958 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
48959 * given the cell's data value. See {@link #setRenderer}. If not specified, the
48960 * default renderer uses the raw data value.
48963 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
48966 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
48970 * Returns the id of the column at the specified index.
48971 * @param {Number} index The column index
48972 * @return {String} the id
48974 getColumnId : function(index){
48975 return this.config[index].id;
48979 * Returns the column for a specified id.
48980 * @param {String} id The column id
48981 * @return {Object} the column
48983 getColumnById : function(id){
48984 return this.lookup[id];
48989 * Returns the column for a specified dataIndex.
48990 * @param {String} dataIndex The column dataIndex
48991 * @return {Object|Boolean} the column or false if not found
48993 getColumnByDataIndex: function(dataIndex){
48994 var index = this.findColumnIndex(dataIndex);
48995 return index > -1 ? this.config[index] : false;
48999 * Returns the index for a specified column id.
49000 * @param {String} id The column id
49001 * @return {Number} the index, or -1 if not found
49003 getIndexById : function(id){
49004 for(var i = 0, len = this.config.length; i < len; i++){
49005 if(this.config[i].id == id){
49013 * Returns the index for a specified column dataIndex.
49014 * @param {String} dataIndex The column dataIndex
49015 * @return {Number} the index, or -1 if not found
49018 findColumnIndex : function(dataIndex){
49019 for(var i = 0, len = this.config.length; i < len; i++){
49020 if(this.config[i].dataIndex == dataIndex){
49028 moveColumn : function(oldIndex, newIndex){
49029 var c = this.config[oldIndex];
49030 this.config.splice(oldIndex, 1);
49031 this.config.splice(newIndex, 0, c);
49032 this.dataMap = null;
49033 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49036 isLocked : function(colIndex){
49037 return this.config[colIndex].locked === true;
49040 setLocked : function(colIndex, value, suppressEvent){
49041 if(this.isLocked(colIndex) == value){
49044 this.config[colIndex].locked = value;
49045 if(!suppressEvent){
49046 this.fireEvent("columnlockchange", this, colIndex, value);
49050 getTotalLockedWidth : function(){
49051 var totalWidth = 0;
49052 for(var i = 0; i < this.config.length; i++){
49053 if(this.isLocked(i) && !this.isHidden(i)){
49054 this.totalWidth += this.getColumnWidth(i);
49060 getLockedCount : function(){
49061 for(var i = 0, len = this.config.length; i < len; i++){
49062 if(!this.isLocked(i)){
49069 * Returns the number of columns.
49072 getColumnCount : function(visibleOnly){
49073 if(visibleOnly === true){
49075 for(var i = 0, len = this.config.length; i < len; i++){
49076 if(!this.isHidden(i)){
49082 return this.config.length;
49086 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49087 * @param {Function} fn
49088 * @param {Object} scope (optional)
49089 * @return {Array} result
49091 getColumnsBy : function(fn, scope){
49093 for(var i = 0, len = this.config.length; i < len; i++){
49094 var c = this.config[i];
49095 if(fn.call(scope||this, c, i) === true){
49103 * Returns true if the specified column is sortable.
49104 * @param {Number} col The column index
49105 * @return {Boolean}
49107 isSortable : function(col){
49108 if(typeof this.config[col].sortable == "undefined"){
49109 return this.defaultSortable;
49111 return this.config[col].sortable;
49115 * Returns the rendering (formatting) function defined for the column.
49116 * @param {Number} col The column index.
49117 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49119 getRenderer : function(col){
49120 if(!this.config[col].renderer){
49121 return Roo.grid.ColumnModel.defaultRenderer;
49123 return this.config[col].renderer;
49127 * Sets the rendering (formatting) function for a column.
49128 * @param {Number} col The column index
49129 * @param {Function} fn The function to use to process the cell's raw data
49130 * to return HTML markup for the grid view. The render function is called with
49131 * the following parameters:<ul>
49132 * <li>Data value.</li>
49133 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49134 * <li>css A CSS style string to apply to the table cell.</li>
49135 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49136 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49137 * <li>Row index</li>
49138 * <li>Column index</li>
49139 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49141 setRenderer : function(col, fn){
49142 this.config[col].renderer = fn;
49146 * Returns the width for the specified column.
49147 * @param {Number} col The column index
49150 getColumnWidth : function(col){
49151 return this.config[col].width || this.defaultWidth;
49155 * Sets the width for a column.
49156 * @param {Number} col The column index
49157 * @param {Number} width The new width
49159 setColumnWidth : function(col, width, suppressEvent){
49160 this.config[col].width = width;
49161 this.totalWidth = null;
49162 if(!suppressEvent){
49163 this.fireEvent("widthchange", this, col, width);
49168 * Returns the total width of all columns.
49169 * @param {Boolean} includeHidden True to include hidden column widths
49172 getTotalWidth : function(includeHidden){
49173 if(!this.totalWidth){
49174 this.totalWidth = 0;
49175 for(var i = 0, len = this.config.length; i < len; i++){
49176 if(includeHidden || !this.isHidden(i)){
49177 this.totalWidth += this.getColumnWidth(i);
49181 return this.totalWidth;
49185 * Returns the header for the specified column.
49186 * @param {Number} col The column index
49189 getColumnHeader : function(col){
49190 return this.config[col].header;
49194 * Sets the header for a column.
49195 * @param {Number} col The column index
49196 * @param {String} header The new header
49198 setColumnHeader : function(col, header){
49199 this.config[col].header = header;
49200 this.fireEvent("headerchange", this, col, header);
49204 * Returns the tooltip for the specified column.
49205 * @param {Number} col The column index
49208 getColumnTooltip : function(col){
49209 return this.config[col].tooltip;
49212 * Sets the tooltip for a column.
49213 * @param {Number} col The column index
49214 * @param {String} tooltip The new tooltip
49216 setColumnTooltip : function(col, tooltip){
49217 this.config[col].tooltip = tooltip;
49221 * Returns the dataIndex for the specified column.
49222 * @param {Number} col The column index
49225 getDataIndex : function(col){
49226 return this.config[col].dataIndex;
49230 * Sets the dataIndex for a column.
49231 * @param {Number} col The column index
49232 * @param {Number} dataIndex The new dataIndex
49234 setDataIndex : function(col, dataIndex){
49235 this.config[col].dataIndex = dataIndex;
49241 * Returns true if the cell is editable.
49242 * @param {Number} colIndex The column index
49243 * @param {Number} rowIndex The row index
49244 * @return {Boolean}
49246 isCellEditable : function(colIndex, rowIndex){
49247 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49251 * Returns the editor defined for the cell/column.
49252 * return false or null to disable editing.
49253 * @param {Number} colIndex The column index
49254 * @param {Number} rowIndex The row index
49257 getCellEditor : function(colIndex, rowIndex){
49258 return this.config[colIndex].editor;
49262 * Sets if a column is editable.
49263 * @param {Number} col The column index
49264 * @param {Boolean} editable True if the column is editable
49266 setEditable : function(col, editable){
49267 this.config[col].editable = editable;
49272 * Returns true if the column is hidden.
49273 * @param {Number} colIndex The column index
49274 * @return {Boolean}
49276 isHidden : function(colIndex){
49277 return this.config[colIndex].hidden;
49282 * Returns true if the column width cannot be changed
49284 isFixed : function(colIndex){
49285 return this.config[colIndex].fixed;
49289 * Returns true if the column can be resized
49290 * @return {Boolean}
49292 isResizable : function(colIndex){
49293 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49296 * Sets if a column is hidden.
49297 * @param {Number} colIndex The column index
49298 * @param {Boolean} hidden True if the column is hidden
49300 setHidden : function(colIndex, hidden){
49301 this.config[colIndex].hidden = hidden;
49302 this.totalWidth = null;
49303 this.fireEvent("hiddenchange", this, colIndex, hidden);
49307 * Sets the editor for a column.
49308 * @param {Number} col The column index
49309 * @param {Object} editor The editor object
49311 setEditor : function(col, editor){
49312 this.config[col].editor = editor;
49316 Roo.grid.ColumnModel.defaultRenderer = function(value){
49317 if(typeof value == "string" && value.length < 1){
49323 // Alias for backwards compatibility
49324 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49327 * Ext JS Library 1.1.1
49328 * Copyright(c) 2006-2007, Ext JS, LLC.
49330 * Originally Released Under LGPL - original licence link has changed is not relivant.
49333 * <script type="text/javascript">
49337 * @class Roo.grid.AbstractSelectionModel
49338 * @extends Roo.util.Observable
49339 * Abstract base class for grid SelectionModels. It provides the interface that should be
49340 * implemented by descendant classes. This class should not be directly instantiated.
49343 Roo.grid.AbstractSelectionModel = function(){
49344 this.locked = false;
49345 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49348 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49349 /** @ignore Called by the grid automatically. Do not call directly. */
49350 init : function(grid){
49356 * Locks the selections.
49359 this.locked = true;
49363 * Unlocks the selections.
49365 unlock : function(){
49366 this.locked = false;
49370 * Returns true if the selections are locked.
49371 * @return {Boolean}
49373 isLocked : function(){
49374 return this.locked;
49378 * Ext JS Library 1.1.1
49379 * Copyright(c) 2006-2007, Ext JS, LLC.
49381 * Originally Released Under LGPL - original licence link has changed is not relivant.
49384 * <script type="text/javascript">
49387 * @extends Roo.grid.AbstractSelectionModel
49388 * @class Roo.grid.RowSelectionModel
49389 * The default SelectionModel used by {@link Roo.grid.Grid}.
49390 * It supports multiple selections and keyboard selection/navigation.
49392 * @param {Object} config
49394 Roo.grid.RowSelectionModel = function(config){
49395 Roo.apply(this, config);
49396 this.selections = new Roo.util.MixedCollection(false, function(o){
49401 this.lastActive = false;
49405 * @event selectionchange
49406 * Fires when the selection changes
49407 * @param {SelectionModel} this
49409 "selectionchange" : true,
49411 * @event afterselectionchange
49412 * Fires after the selection changes (eg. by key press or clicking)
49413 * @param {SelectionModel} this
49415 "afterselectionchange" : true,
49417 * @event beforerowselect
49418 * Fires when a row is selected being selected, return false to cancel.
49419 * @param {SelectionModel} this
49420 * @param {Number} rowIndex The selected index
49421 * @param {Boolean} keepExisting False if other selections will be cleared
49423 "beforerowselect" : true,
49426 * Fires when a row is selected.
49427 * @param {SelectionModel} this
49428 * @param {Number} rowIndex The selected index
49429 * @param {Roo.data.Record} r The record
49431 "rowselect" : true,
49433 * @event rowdeselect
49434 * Fires when a row is deselected.
49435 * @param {SelectionModel} this
49436 * @param {Number} rowIndex The selected index
49438 "rowdeselect" : true
49440 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49441 this.locked = false;
49444 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49446 * @cfg {Boolean} singleSelect
49447 * True to allow selection of only one row at a time (defaults to false)
49449 singleSelect : false,
49452 initEvents : function(){
49454 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49455 this.grid.on("mousedown", this.handleMouseDown, this);
49456 }else{ // allow click to work like normal
49457 this.grid.on("rowclick", this.handleDragableRowClick, this);
49460 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49461 "up" : function(e){
49463 this.selectPrevious(e.shiftKey);
49464 }else if(this.last !== false && this.lastActive !== false){
49465 var last = this.last;
49466 this.selectRange(this.last, this.lastActive-1);
49467 this.grid.getView().focusRow(this.lastActive);
49468 if(last !== false){
49472 this.selectFirstRow();
49474 this.fireEvent("afterselectionchange", this);
49476 "down" : function(e){
49478 this.selectNext(e.shiftKey);
49479 }else if(this.last !== false && this.lastActive !== false){
49480 var last = this.last;
49481 this.selectRange(this.last, this.lastActive+1);
49482 this.grid.getView().focusRow(this.lastActive);
49483 if(last !== false){
49487 this.selectFirstRow();
49489 this.fireEvent("afterselectionchange", this);
49494 var view = this.grid.view;
49495 view.on("refresh", this.onRefresh, this);
49496 view.on("rowupdated", this.onRowUpdated, this);
49497 view.on("rowremoved", this.onRemove, this);
49501 onRefresh : function(){
49502 var ds = this.grid.dataSource, i, v = this.grid.view;
49503 var s = this.selections;
49504 s.each(function(r){
49505 if((i = ds.indexOfId(r.id)) != -1){
49514 onRemove : function(v, index, r){
49515 this.selections.remove(r);
49519 onRowUpdated : function(v, index, r){
49520 if(this.isSelected(r)){
49521 v.onRowSelect(index);
49527 * @param {Array} records The records to select
49528 * @param {Boolean} keepExisting (optional) True to keep existing selections
49530 selectRecords : function(records, keepExisting){
49532 this.clearSelections();
49534 var ds = this.grid.dataSource;
49535 for(var i = 0, len = records.length; i < len; i++){
49536 this.selectRow(ds.indexOf(records[i]), true);
49541 * Gets the number of selected rows.
49544 getCount : function(){
49545 return this.selections.length;
49549 * Selects the first row in the grid.
49551 selectFirstRow : function(){
49556 * Select the last row.
49557 * @param {Boolean} keepExisting (optional) True to keep existing selections
49559 selectLastRow : function(keepExisting){
49560 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
49564 * Selects the row immediately following the last selected row.
49565 * @param {Boolean} keepExisting (optional) True to keep existing selections
49567 selectNext : function(keepExisting){
49568 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49569 this.selectRow(this.last+1, keepExisting);
49570 this.grid.getView().focusRow(this.last);
49575 * Selects the row that precedes the last selected row.
49576 * @param {Boolean} keepExisting (optional) True to keep existing selections
49578 selectPrevious : function(keepExisting){
49580 this.selectRow(this.last-1, keepExisting);
49581 this.grid.getView().focusRow(this.last);
49586 * Returns the selected records
49587 * @return {Array} Array of selected records
49589 getSelections : function(){
49590 return [].concat(this.selections.items);
49594 * Returns the first selected record.
49597 getSelected : function(){
49598 return this.selections.itemAt(0);
49603 * Clears all selections.
49605 clearSelections : function(fast){
49606 if(this.locked) return;
49608 var ds = this.grid.dataSource;
49609 var s = this.selections;
49610 s.each(function(r){
49611 this.deselectRow(ds.indexOfId(r.id));
49615 this.selections.clear();
49622 * Selects all rows.
49624 selectAll : function(){
49625 if(this.locked) return;
49626 this.selections.clear();
49627 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
49628 this.selectRow(i, true);
49633 * Returns True if there is a selection.
49634 * @return {Boolean}
49636 hasSelection : function(){
49637 return this.selections.length > 0;
49641 * Returns True if the specified row is selected.
49642 * @param {Number/Record} record The record or index of the record to check
49643 * @return {Boolean}
49645 isSelected : function(index){
49646 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
49647 return (r && this.selections.key(r.id) ? true : false);
49651 * Returns True if the specified record id is selected.
49652 * @param {String} id The id of record to check
49653 * @return {Boolean}
49655 isIdSelected : function(id){
49656 return (this.selections.key(id) ? true : false);
49660 handleMouseDown : function(e, t){
49661 var view = this.grid.getView(), rowIndex;
49662 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
49665 if(e.shiftKey && this.last !== false){
49666 var last = this.last;
49667 this.selectRange(last, rowIndex, e.ctrlKey);
49668 this.last = last; // reset the last
49669 view.focusRow(rowIndex);
49671 var isSelected = this.isSelected(rowIndex);
49672 if(e.button !== 0 && isSelected){
49673 view.focusRow(rowIndex);
49674 }else if(e.ctrlKey && isSelected){
49675 this.deselectRow(rowIndex);
49676 }else if(!isSelected){
49677 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
49678 view.focusRow(rowIndex);
49681 this.fireEvent("afterselectionchange", this);
49684 handleDragableRowClick : function(grid, rowIndex, e)
49686 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
49687 this.selectRow(rowIndex, false);
49688 grid.view.focusRow(rowIndex);
49689 this.fireEvent("afterselectionchange", this);
49694 * Selects multiple rows.
49695 * @param {Array} rows Array of the indexes of the row to select
49696 * @param {Boolean} keepExisting (optional) True to keep existing selections
49698 selectRows : function(rows, keepExisting){
49700 this.clearSelections();
49702 for(var i = 0, len = rows.length; i < len; i++){
49703 this.selectRow(rows[i], true);
49708 * Selects a range of rows. All rows in between startRow and endRow are also selected.
49709 * @param {Number} startRow The index of the first row in the range
49710 * @param {Number} endRow The index of the last row in the range
49711 * @param {Boolean} keepExisting (optional) True to retain existing selections
49713 selectRange : function(startRow, endRow, keepExisting){
49714 if(this.locked) return;
49716 this.clearSelections();
49718 if(startRow <= endRow){
49719 for(var i = startRow; i <= endRow; i++){
49720 this.selectRow(i, true);
49723 for(var i = startRow; i >= endRow; i--){
49724 this.selectRow(i, true);
49730 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
49731 * @param {Number} startRow The index of the first row in the range
49732 * @param {Number} endRow The index of the last row in the range
49734 deselectRange : function(startRow, endRow, preventViewNotify){
49735 if(this.locked) return;
49736 for(var i = startRow; i <= endRow; i++){
49737 this.deselectRow(i, preventViewNotify);
49743 * @param {Number} row The index of the row to select
49744 * @param {Boolean} keepExisting (optional) True to keep existing selections
49746 selectRow : function(index, keepExisting, preventViewNotify){
49747 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
49748 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
49749 if(!keepExisting || this.singleSelect){
49750 this.clearSelections();
49752 var r = this.grid.dataSource.getAt(index);
49753 this.selections.add(r);
49754 this.last = this.lastActive = index;
49755 if(!preventViewNotify){
49756 this.grid.getView().onRowSelect(index);
49758 this.fireEvent("rowselect", this, index, r);
49759 this.fireEvent("selectionchange", this);
49765 * @param {Number} row The index of the row to deselect
49767 deselectRow : function(index, preventViewNotify){
49768 if(this.locked) return;
49769 if(this.last == index){
49772 if(this.lastActive == index){
49773 this.lastActive = false;
49775 var r = this.grid.dataSource.getAt(index);
49776 this.selections.remove(r);
49777 if(!preventViewNotify){
49778 this.grid.getView().onRowDeselect(index);
49780 this.fireEvent("rowdeselect", this, index);
49781 this.fireEvent("selectionchange", this);
49785 restoreLast : function(){
49787 this.last = this._last;
49792 acceptsNav : function(row, col, cm){
49793 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49797 onEditorKey : function(field, e){
49798 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49803 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49805 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49807 }else if(k == e.ENTER && !e.ctrlKey){
49811 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
49813 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
49815 }else if(k == e.ESC){
49819 g.startEditing(newCell[0], newCell[1]);
49824 * Ext JS Library 1.1.1
49825 * Copyright(c) 2006-2007, Ext JS, LLC.
49827 * Originally Released Under LGPL - original licence link has changed is not relivant.
49830 * <script type="text/javascript">
49833 * @class Roo.grid.CellSelectionModel
49834 * @extends Roo.grid.AbstractSelectionModel
49835 * This class provides the basic implementation for cell selection in a grid.
49837 * @param {Object} config The object containing the configuration of this model.
49839 Roo.grid.CellSelectionModel = function(config){
49840 Roo.apply(this, config);
49842 this.selection = null;
49846 * @event beforerowselect
49847 * Fires before a cell is selected.
49848 * @param {SelectionModel} this
49849 * @param {Number} rowIndex The selected row index
49850 * @param {Number} colIndex The selected cell index
49852 "beforecellselect" : true,
49854 * @event cellselect
49855 * Fires when a cell is selected.
49856 * @param {SelectionModel} this
49857 * @param {Number} rowIndex The selected row index
49858 * @param {Number} colIndex The selected cell index
49860 "cellselect" : true,
49862 * @event selectionchange
49863 * Fires when the active selection changes.
49864 * @param {SelectionModel} this
49865 * @param {Object} selection null for no selection or an object (o) with two properties
49867 <li>o.record: the record object for the row the selection is in</li>
49868 <li>o.cell: An array of [rowIndex, columnIndex]</li>
49871 "selectionchange" : true
49873 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
49876 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
49879 initEvents : function(){
49880 this.grid.on("mousedown", this.handleMouseDown, this);
49881 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
49882 var view = this.grid.view;
49883 view.on("refresh", this.onViewChange, this);
49884 view.on("rowupdated", this.onRowUpdated, this);
49885 view.on("beforerowremoved", this.clearSelections, this);
49886 view.on("beforerowsinserted", this.clearSelections, this);
49887 if(this.grid.isEditor){
49888 this.grid.on("beforeedit", this.beforeEdit, this);
49893 beforeEdit : function(e){
49894 this.select(e.row, e.column, false, true, e.record);
49898 onRowUpdated : function(v, index, r){
49899 if(this.selection && this.selection.record == r){
49900 v.onCellSelect(index, this.selection.cell[1]);
49905 onViewChange : function(){
49906 this.clearSelections(true);
49910 * Returns the currently selected cell,.
49911 * @return {Array} The selected cell (row, column) or null if none selected.
49913 getSelectedCell : function(){
49914 return this.selection ? this.selection.cell : null;
49918 * Clears all selections.
49919 * @param {Boolean} true to prevent the gridview from being notified about the change.
49921 clearSelections : function(preventNotify){
49922 var s = this.selection;
49924 if(preventNotify !== true){
49925 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
49927 this.selection = null;
49928 this.fireEvent("selectionchange", this, null);
49933 * Returns true if there is a selection.
49934 * @return {Boolean}
49936 hasSelection : function(){
49937 return this.selection ? true : false;
49941 handleMouseDown : function(e, t){
49942 var v = this.grid.getView();
49943 if(this.isLocked()){
49946 var row = v.findRowIndex(t);
49947 var cell = v.findCellIndex(t);
49948 if(row !== false && cell !== false){
49949 this.select(row, cell);
49955 * @param {Number} rowIndex
49956 * @param {Number} collIndex
49958 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
49959 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
49960 this.clearSelections();
49961 r = r || this.grid.dataSource.getAt(rowIndex);
49964 cell : [rowIndex, colIndex]
49966 if(!preventViewNotify){
49967 var v = this.grid.getView();
49968 v.onCellSelect(rowIndex, colIndex);
49969 if(preventFocus !== true){
49970 v.focusCell(rowIndex, colIndex);
49973 this.fireEvent("cellselect", this, rowIndex, colIndex);
49974 this.fireEvent("selectionchange", this, this.selection);
49979 isSelectable : function(rowIndex, colIndex, cm){
49980 return !cm.isHidden(colIndex);
49984 handleKeyDown : function(e){
49985 Roo.log('Cell Sel Model handleKeyDown');
49986 if(!e.isNavKeyPress()){
49989 var g = this.grid, s = this.selection;
49992 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
49994 this.select(cell[0], cell[1]);
49999 var walk = function(row, col, step){
50000 return g.walkCells(row, col, step, sm.isSelectable, sm);
50002 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
50007 // handled by onEditorKey
50008 if (g.isEditor && g.editing) {
50012 newCell = walk(r, c-1, -1);
50014 newCell = walk(r, c+1, 1);
50018 newCell = walk(r+1, c, 1);
50021 newCell = walk(r-1, c, -1);
50024 newCell = walk(r, c+1, 1);
50027 newCell = walk(r, c-1, -1);
50030 if(g.isEditor && !g.editing){
50031 g.startEditing(r, c);
50038 this.select(newCell[0], newCell[1]);
50043 acceptsNav : function(row, col, cm){
50044 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50047 onEditorKey : function(field, e){
50049 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50050 ///Roo.log('onEditorKey' + k);
50054 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50056 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50059 }else if(k == e.ENTER && !e.ctrlKey){
50062 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50063 }else if(k == e.ESC){
50069 //Roo.log('next cell after edit');
50070 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50075 * Ext JS Library 1.1.1
50076 * Copyright(c) 2006-2007, Ext JS, LLC.
50078 * Originally Released Under LGPL - original licence link has changed is not relivant.
50081 * <script type="text/javascript">
50085 * @class Roo.grid.EditorGrid
50086 * @extends Roo.grid.Grid
50087 * Class for creating and editable grid.
50088 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50089 * The container MUST have some type of size defined for the grid to fill. The container will be
50090 * automatically set to position relative if it isn't already.
50091 * @param {Object} dataSource The data model to bind to
50092 * @param {Object} colModel The column model with info about this grid's columns
50094 Roo.grid.EditorGrid = function(container, config){
50095 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50096 this.getGridEl().addClass("xedit-grid");
50098 if(!this.selModel){
50099 this.selModel = new Roo.grid.CellSelectionModel();
50102 this.activeEditor = null;
50106 * @event beforeedit
50107 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50108 * <ul style="padding:5px;padding-left:16px;">
50109 * <li>grid - This grid</li>
50110 * <li>record - The record being edited</li>
50111 * <li>field - The field name being edited</li>
50112 * <li>value - The value for the field being edited.</li>
50113 * <li>row - The grid row index</li>
50114 * <li>column - The grid column index</li>
50115 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50117 * @param {Object} e An edit event (see above for description)
50119 "beforeedit" : true,
50122 * Fires after a cell is edited. <br />
50123 * <ul style="padding:5px;padding-left:16px;">
50124 * <li>grid - This grid</li>
50125 * <li>record - The record being edited</li>
50126 * <li>field - The field name being edited</li>
50127 * <li>value - The value being set</li>
50128 * <li>originalValue - The original value for the field, before the edit.</li>
50129 * <li>row - The grid row index</li>
50130 * <li>column - The grid column index</li>
50132 * @param {Object} e An edit event (see above for description)
50134 "afteredit" : true,
50136 * @event validateedit
50137 * Fires after a cell is edited, but before the value is set in the record.
50138 * You can use this to modify the value being set in the field, Return false
50139 * to cancel the change. The edit event object has the following properties <br />
50140 * <ul style="padding:5px;padding-left:16px;">
50141 * <li>editor - This editor</li>
50142 * <li>grid - This grid</li>
50143 * <li>record - The record being edited</li>
50144 * <li>field - The field name being edited</li>
50145 * <li>value - The value being set</li>
50146 * <li>originalValue - The original value for the field, before the edit.</li>
50147 * <li>row - The grid row index</li>
50148 * <li>column - The grid column index</li>
50149 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50151 * @param {Object} e An edit event (see above for description)
50153 "validateedit" : true
50155 this.on("bodyscroll", this.stopEditing, this);
50156 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50159 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50161 * @cfg {Number} clicksToEdit
50162 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50169 trackMouseOver: false, // causes very odd FF errors
50171 onCellDblClick : function(g, row, col){
50172 this.startEditing(row, col);
50175 onEditComplete : function(ed, value, startValue){
50176 this.editing = false;
50177 this.activeEditor = null;
50178 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50180 var field = this.colModel.getDataIndex(ed.col);
50185 originalValue: startValue,
50192 if(String(value) !== String(startValue)){
50194 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50195 r.set(field, e.value);
50196 // if we are dealing with a combo box..
50197 // then we also set the 'name' colum to be the displayField
50198 if (ed.field.displayField && ed.field.name) {
50199 r.set(ed.field.name, ed.field.el.dom.value);
50202 delete e.cancel; //?? why!!!
50203 this.fireEvent("afteredit", e);
50206 this.fireEvent("afteredit", e); // always fire it!
50208 this.view.focusCell(ed.row, ed.col);
50212 * Starts editing the specified for the specified row/column
50213 * @param {Number} rowIndex
50214 * @param {Number} colIndex
50216 startEditing : function(row, col){
50217 this.stopEditing();
50218 if(this.colModel.isCellEditable(col, row)){
50219 this.view.ensureVisible(row, col, true);
50220 var r = this.dataSource.getAt(row);
50221 var field = this.colModel.getDataIndex(col);
50226 value: r.data[field],
50231 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50232 this.editing = true;
50233 var ed = this.colModel.getCellEditor(col, row);
50239 ed.render(ed.parentEl || document.body);
50242 (function(){ // complex but required for focus issues in safari, ie and opera
50246 ed.on("complete", this.onEditComplete, this, {single: true});
50247 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50248 this.activeEditor = ed;
50249 var v = r.data[field];
50250 ed.startEdit(this.view.getCell(row, col), v);
50251 // combo's with 'displayField and name set
50252 if (ed.field.displayField && ed.field.name) {
50253 ed.field.el.dom.value = r.data[ed.field.name];
50257 }).defer(50, this);
50263 * Stops any active editing
50265 stopEditing : function(){
50266 if(this.activeEditor){
50267 this.activeEditor.completeEdit();
50269 this.activeEditor = null;
50273 * Ext JS Library 1.1.1
50274 * Copyright(c) 2006-2007, Ext JS, LLC.
50276 * Originally Released Under LGPL - original licence link has changed is not relivant.
50279 * <script type="text/javascript">
50282 // private - not really -- you end up using it !
50283 // This is a support class used internally by the Grid components
50286 * @class Roo.grid.GridEditor
50287 * @extends Roo.Editor
50288 * Class for creating and editable grid elements.
50289 * @param {Object} config any settings (must include field)
50291 Roo.grid.GridEditor = function(field, config){
50292 if (!config && field.field) {
50294 field = Roo.factory(config.field, Roo.form);
50296 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50297 field.monitorTab = false;
50300 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50303 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50306 alignment: "tl-tl",
50309 cls: "x-small-editor x-grid-editor",
50314 * Ext JS Library 1.1.1
50315 * Copyright(c) 2006-2007, Ext JS, LLC.
50317 * Originally Released Under LGPL - original licence link has changed is not relivant.
50320 * <script type="text/javascript">
50325 Roo.grid.PropertyRecord = Roo.data.Record.create([
50326 {name:'name',type:'string'}, 'value'
50330 Roo.grid.PropertyStore = function(grid, source){
50332 this.store = new Roo.data.Store({
50333 recordType : Roo.grid.PropertyRecord
50335 this.store.on('update', this.onUpdate, this);
50337 this.setSource(source);
50339 Roo.grid.PropertyStore.superclass.constructor.call(this);
50344 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50345 setSource : function(o){
50347 this.store.removeAll();
50350 if(this.isEditableValue(o[k])){
50351 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50354 this.store.loadRecords({records: data}, {}, true);
50357 onUpdate : function(ds, record, type){
50358 if(type == Roo.data.Record.EDIT){
50359 var v = record.data['value'];
50360 var oldValue = record.modified['value'];
50361 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50362 this.source[record.id] = v;
50364 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50371 getProperty : function(row){
50372 return this.store.getAt(row);
50375 isEditableValue: function(val){
50376 if(val && val instanceof Date){
50378 }else if(typeof val == 'object' || typeof val == 'function'){
50384 setValue : function(prop, value){
50385 this.source[prop] = value;
50386 this.store.getById(prop).set('value', value);
50389 getSource : function(){
50390 return this.source;
50394 Roo.grid.PropertyColumnModel = function(grid, store){
50397 g.PropertyColumnModel.superclass.constructor.call(this, [
50398 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50399 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50401 this.store = store;
50402 this.bselect = Roo.DomHelper.append(document.body, {
50403 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50404 {tag: 'option', value: 'true', html: 'true'},
50405 {tag: 'option', value: 'false', html: 'false'}
50408 Roo.id(this.bselect);
50411 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50412 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50413 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50414 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50415 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50417 this.renderCellDelegate = this.renderCell.createDelegate(this);
50418 this.renderPropDelegate = this.renderProp.createDelegate(this);
50421 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50425 valueText : 'Value',
50427 dateFormat : 'm/j/Y',
50430 renderDate : function(dateVal){
50431 return dateVal.dateFormat(this.dateFormat);
50434 renderBool : function(bVal){
50435 return bVal ? 'true' : 'false';
50438 isCellEditable : function(colIndex, rowIndex){
50439 return colIndex == 1;
50442 getRenderer : function(col){
50444 this.renderCellDelegate : this.renderPropDelegate;
50447 renderProp : function(v){
50448 return this.getPropertyName(v);
50451 renderCell : function(val){
50453 if(val instanceof Date){
50454 rv = this.renderDate(val);
50455 }else if(typeof val == 'boolean'){
50456 rv = this.renderBool(val);
50458 return Roo.util.Format.htmlEncode(rv);
50461 getPropertyName : function(name){
50462 var pn = this.grid.propertyNames;
50463 return pn && pn[name] ? pn[name] : name;
50466 getCellEditor : function(colIndex, rowIndex){
50467 var p = this.store.getProperty(rowIndex);
50468 var n = p.data['name'], val = p.data['value'];
50470 if(typeof(this.grid.customEditors[n]) == 'string'){
50471 return this.editors[this.grid.customEditors[n]];
50473 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50474 return this.grid.customEditors[n];
50476 if(val instanceof Date){
50477 return this.editors['date'];
50478 }else if(typeof val == 'number'){
50479 return this.editors['number'];
50480 }else if(typeof val == 'boolean'){
50481 return this.editors['boolean'];
50483 return this.editors['string'];
50489 * @class Roo.grid.PropertyGrid
50490 * @extends Roo.grid.EditorGrid
50491 * This class represents the interface of a component based property grid control.
50492 * <br><br>Usage:<pre><code>
50493 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50501 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50502 * The container MUST have some type of size defined for the grid to fill. The container will be
50503 * automatically set to position relative if it isn't already.
50504 * @param {Object} config A config object that sets properties on this grid.
50506 Roo.grid.PropertyGrid = function(container, config){
50507 config = config || {};
50508 var store = new Roo.grid.PropertyStore(this);
50509 this.store = store;
50510 var cm = new Roo.grid.PropertyColumnModel(this, store);
50511 store.store.sort('name', 'ASC');
50512 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50515 enableColLock:false,
50516 enableColumnMove:false,
50518 trackMouseOver: false,
50521 this.getGridEl().addClass('x-props-grid');
50522 this.lastEditRow = null;
50523 this.on('columnresize', this.onColumnResize, this);
50526 * @event beforepropertychange
50527 * Fires before a property changes (return false to stop?)
50528 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50529 * @param {String} id Record Id
50530 * @param {String} newval New Value
50531 * @param {String} oldval Old Value
50533 "beforepropertychange": true,
50535 * @event propertychange
50536 * Fires after a property changes
50537 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50538 * @param {String} id Record Id
50539 * @param {String} newval New Value
50540 * @param {String} oldval Old Value
50542 "propertychange": true
50544 this.customEditors = this.customEditors || {};
50546 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50549 * @cfg {Object} customEditors map of colnames=> custom editors.
50550 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50551 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50552 * false disables editing of the field.
50556 * @cfg {Object} propertyNames map of property Names to their displayed value
50559 render : function(){
50560 Roo.grid.PropertyGrid.superclass.render.call(this);
50561 this.autoSize.defer(100, this);
50564 autoSize : function(){
50565 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50567 this.view.fitColumns();
50571 onColumnResize : function(){
50572 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
50576 * Sets the data for the Grid
50577 * accepts a Key => Value object of all the elements avaiable.
50578 * @param {Object} data to appear in grid.
50580 setSource : function(source){
50581 this.store.setSource(source);
50585 * Gets all the data from the grid.
50586 * @return {Object} data data stored in grid
50588 getSource : function(){
50589 return this.store.getSource();
50593 * Ext JS Library 1.1.1
50594 * Copyright(c) 2006-2007, Ext JS, LLC.
50596 * Originally Released Under LGPL - original licence link has changed is not relivant.
50599 * <script type="text/javascript">
50603 * @class Roo.LoadMask
50604 * A simple utility class for generically masking elements while loading data. If the element being masked has
50605 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
50606 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
50607 * element's UpdateManager load indicator and will be destroyed after the initial load.
50609 * Create a new LoadMask
50610 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
50611 * @param {Object} config The config object
50613 Roo.LoadMask = function(el, config){
50614 this.el = Roo.get(el);
50615 Roo.apply(this, config);
50617 this.store.on('beforeload', this.onBeforeLoad, this);
50618 this.store.on('load', this.onLoad, this);
50619 this.store.on('loadexception', this.onLoad, this);
50620 this.removeMask = false;
50622 var um = this.el.getUpdateManager();
50623 um.showLoadIndicator = false; // disable the default indicator
50624 um.on('beforeupdate', this.onBeforeLoad, this);
50625 um.on('update', this.onLoad, this);
50626 um.on('failure', this.onLoad, this);
50627 this.removeMask = true;
50631 Roo.LoadMask.prototype = {
50633 * @cfg {Boolean} removeMask
50634 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
50635 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
50638 * @cfg {String} msg
50639 * The text to display in a centered loading message box (defaults to 'Loading...')
50641 msg : 'Loading...',
50643 * @cfg {String} msgCls
50644 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
50646 msgCls : 'x-mask-loading',
50649 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
50655 * Disables the mask to prevent it from being displayed
50657 disable : function(){
50658 this.disabled = true;
50662 * Enables the mask so that it can be displayed
50664 enable : function(){
50665 this.disabled = false;
50669 onLoad : function(){
50670 this.el.unmask(this.removeMask);
50674 onBeforeLoad : function(){
50675 if(!this.disabled){
50676 this.el.mask(this.msg, this.msgCls);
50681 destroy : function(){
50683 this.store.un('beforeload', this.onBeforeLoad, this);
50684 this.store.un('load', this.onLoad, this);
50685 this.store.un('loadexception', this.onLoad, this);
50687 var um = this.el.getUpdateManager();
50688 um.un('beforeupdate', this.onBeforeLoad, this);
50689 um.un('update', this.onLoad, this);
50690 um.un('failure', this.onLoad, this);
50695 * Ext JS Library 1.1.1
50696 * Copyright(c) 2006-2007, Ext JS, LLC.
50698 * Originally Released Under LGPL - original licence link has changed is not relivant.
50701 * <script type="text/javascript">
50703 Roo.XTemplate = function(){
50704 Roo.XTemplate.superclass.constructor.apply(this, arguments);
50707 s = ['<tpl>', s, '</tpl>'].join('');
50709 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
50711 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
50712 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
50713 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
50717 while(m = s.match(re)){
50718 var m2 = m[0].match(nameRe);
50719 var m3 = m[0].match(ifRe);
50720 var m4 = m[0].match(execRe);
50721 var exp = null, fn = null, exec = null;
50722 var name = m2 && m2[1] ? m2[1] : '';
50724 exp = m3 && m3[1] ? m3[1] : null;
50726 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
50730 exp = m4 && m4[1] ? m4[1] : null;
50732 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
50737 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
50738 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
50739 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
50749 s = s.replace(m[0], '{xtpl'+ id + '}');
50752 for(var i = tpls.length-1; i >= 0; --i){
50753 this.compileTpl(tpls[i]);
50755 this.master = tpls[tpls.length-1];
50758 Roo.extend(Roo.XTemplate, Roo.Template, {
50760 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
50762 applySubTemplate : function(id, values, parent){
50763 var t = this.tpls[id];
50764 if(t.test && !t.test.call(this, values, parent)){
50767 if(t.exec && t.exec.call(this, values, parent)){
50770 var vs = t.target ? t.target.call(this, values, parent) : values;
50771 parent = t.target ? values : parent;
50772 if(t.target && vs instanceof Array){
50774 for(var i = 0, len = vs.length; i < len; i++){
50775 buf[buf.length] = t.compiled.call(this, vs[i], parent);
50777 return buf.join('');
50779 return t.compiled.call(this, vs, parent);
50782 compileTpl : function(tpl){
50783 var fm = Roo.util.Format;
50784 var useF = this.disableFormats !== true;
50785 var sep = Roo.isGecko ? "+" : ",";
50786 var fn = function(m, name, format, args){
50787 if(name.substr(0, 4) == 'xtpl'){
50788 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
50791 if(name.indexOf('.') != -1){
50794 v = "values['" + name + "']";
50796 if(format && useF){
50797 args = args ? ',' + args : "";
50798 if(format.substr(0, 5) != "this."){
50799 format = "fm." + format + '(';
50801 format = 'this.call("'+ format.substr(5) + '", ';
50805 args= ''; format = "("+v+" === undefined ? '' : ";
50807 return "'"+ sep + format + v + args + ")"+sep+"'";
50810 // branched to use + in gecko and [].join() in others
50812 body = "tpl.compiled = function(values, parent){ return '" +
50813 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
50816 body = ["tpl.compiled = function(values, parent){ return ['"];
50817 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
50818 body.push("'].join('');};");
50819 body = body.join('');
50821 /** eval:var:zzzzzzz */
50826 applyTemplate : function(values){
50827 return this.master.compiled.call(this, values, {});
50831 apply : function(){
50832 return this.applyTemplate.apply(this, arguments);
50835 compile : function(){return this;}
50838 Roo.XTemplate.from = function(el){
50839 el = Roo.getDom(el);
50840 return new Roo.XTemplate(el.value || el.innerHTML);
50842 * Original code for Roojs - LGPL
50843 * <script type="text/javascript">
50847 * @class Roo.XComponent
50848 * A delayed Element creator...
50850 * Mypart.xyx = new Roo.XComponent({
50852 parent : 'Mypart.xyz', // empty == document.element.!!
50856 disabled : function() {}
50858 tree : function() { // return an tree of xtype declared components
50862 xtype : 'NestedLayoutPanel',
50867 * @extends Roo.util.Observable
50869 * @param cfg {Object} configuration of component
50872 Roo.XComponent = function(cfg) {
50873 Roo.apply(this, cfg);
50877 * Fires when this the componnt is built
50878 * @param {Roo.XComponent} c the component
50882 * @event buildcomplete
50883 * Fires on the top level element when all elements have been built
50884 * @param {Roo.XComponent} c the top level component.
50886 'buildcomplete' : true
50890 Roo.XComponent.register(this);
50891 this.modules = false;
50892 this.el = false; // where the layout goes..
50896 Roo.extend(Roo.XComponent, Roo.util.Observable, {
50899 * The created element (with Roo.factory())
50900 * @type {Roo.Layout}
50906 * for BC - use el in new code
50907 * @type {Roo.Layout}
50913 * for BC - use el in new code
50914 * @type {Roo.Layout}
50919 * @cfg {Function|boolean} disabled
50920 * If this module is disabled by some rule, return true from the funtion
50925 * @cfg {String} parent
50926 * Name of parent element which it get xtype added to..
50931 * @cfg {String} order
50932 * Used to set the order in which elements are created (usefull for multiple tabs)
50937 * @cfg {String} name
50938 * String to display while loading.
50942 * @cfg {Array} items
50943 * A single item array - the first element is the root of the tree..
50944 * It's done this way to stay compatible with the Xtype system...
50952 Roo.apply(Roo.XComponent, {
50955 * @property buildCompleted
50956 * True when the builder has completed building the interface.
50959 buildCompleted : false,
50962 * @property topModule
50963 * the upper most module - uses document.element as it's constructor.
50970 * @property modules
50971 * array of modules to be created by registration system.
50972 * @type Roo.XComponent
50979 * Register components to be built later.
50981 * This solves the following issues
50982 * - Building is not done on page load, but after an authentication process has occured.
50983 * - Interface elements are registered on page load
50984 * - Parent Interface elements may not be loaded before child, so this handles that..
50991 module : 'Pman.Tab.projectMgr',
50993 parent : 'Pman.layout',
50994 disabled : false, // or use a function..
50997 * * @param {Object} details about module
50999 register : function(obj) {
51000 this.modules.push(obj);
51004 * convert a string to an object..
51008 toObject : function(str)
51010 if (!str || typeof(str) == 'object') {
51013 var ar = str.split('.');
51017 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51019 throw "Module not found : " + str;
51021 Roo.each(ar, function(e) {
51022 if (typeof(o[e]) == 'undefined') {
51023 throw "Module not found : " + str;
51033 * move modules into their correct place in the tree..
51036 preBuild : function ()
51039 Roo.each(this.modules , function (obj)
51041 obj.parent = this.toObject(obj.parent);
51044 this.topModule = obj;
51048 if (!obj.parent.modules) {
51049 obj.parent.modules = new Roo.util.MixedCollection(false,
51050 function(o) { return o.order + '' }
51054 obj.parent.modules.add(obj);
51059 * make a list of modules to build.
51060 * @return {Array} list of modules.
51063 buildOrder : function()
51066 var cmp = function(a,b) {
51067 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51070 if (!this.topModule || !this.topModule.modules) {
51071 throw "No top level modules to build";
51074 // make a flat list in order of modules to build.
51075 var mods = [ this.topModule ];
51078 // add modules to their parents..
51079 var addMod = function(m) {
51080 // Roo.debug && Roo.log(m.modKey);
51084 m.modules.keySort('ASC', cmp );
51085 m.modules.each(addMod);
51087 // not sure if this is used any more..
51089 m.finalize.name = m.name + " (clean up) ";
51090 mods.push(m.finalize);
51094 this.topModule.modules.keySort('ASC', cmp );
51095 this.topModule.modules.each(addMod);
51100 * Build the registered modules.
51101 * @param {Object} parent element.
51102 * @param {Function} optional method to call after module has been added.
51110 var mods = this.buildOrder();
51112 //this.allmods = mods;
51113 //Roo.debug && Roo.log(mods);
51115 if (!mods.length) { // should not happen
51116 throw "NO modules!!!";
51121 // flash it up as modal - so we store the mask!?
51122 Roo.MessageBox.show({ title: 'loading' });
51123 Roo.MessageBox.show({
51124 title: "Please wait...",
51125 msg: "Building Interface...",
51132 var total = mods.length;
51135 var progressRun = function() {
51136 if (!mods.length) {
51137 Roo.debug && Roo.log('hide?');
51138 Roo.MessageBox.hide();
51139 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51143 var m = mods.shift();
51144 Roo.debug && Roo.log(m);
51145 if (typeof(m) == 'function') { // not sure if this is supported any more..
51147 return progressRun.defer(10, _this);
51150 Roo.MessageBox.updateProgress(
51151 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51153 (m.name ? (' - ' + m.name) : '')
51158 var disabled = (typeof(m.disabled) == 'function') ?
51159 m.disabled.call(m.module.disabled) : m.disabled;
51163 return progressRun(); // we do not update the display!
51167 // it's a top level one..
51168 var layoutbase = new Ext.BorderLayout(document.body, {
51174 tabPosition: 'top',
51175 //resizeTabs: true,
51176 alwaysShowTabs: true,
51180 var tree = m.tree();
51181 tree.region = 'center';
51182 m.el = layoutbase.addxtype(tree);
51184 m.layout = m.panel.layout;
51185 return progressRun.defer(10, _this);
51188 var tree = m.tree();
51189 tree.region = tree.region || m.region;
51190 m.el = m.parent.el.addxtype(tree);
51191 m.fireEvent('built', m);
51193 m.layout = m.panel.layout;
51194 progressRun.defer(10, _this);
51197 progressRun.defer(1, _this);
51207 //<script type="text/javascript">
51212 * @extends Roo.LayoutDialog
51213 * A generic Login Dialog..... - only one needed in theory!?!?
51215 * Fires XComponent builder on success...
51218 * username,password, lang = for login actions.
51219 * check = 1 for periodic checking that sesion is valid.
51220 * passwordRequest = email request password
51221 * logout = 1 = to logout
51223 * Affects: (this id="????" elements)
51224 * loading (removed) (used to indicate application is loading)
51225 * loading-mask (hides) (used to hide application when it's building loading)
51231 * Myapp.login = Roo.Login({
51247 Roo.Login = function(cfg)
51253 Roo.apply(this,cfg);
51255 Roo.onReady(function() {
51261 Roo.Login.superclass.constructor.call(this, this);
51262 //this.addxtype(this.items[0]);
51268 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51271 * @cfg {String} method
51272 * Method used to query for login details.
51277 * @cfg {String} url
51278 * URL to query login data. - eg. baseURL + '/Login.php'
51284 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51289 * @property checkFails
51290 * Number of times we have attempted to get authentication check, and failed.
51295 * @property intervalID
51296 * The window interval that does the constant login checking.
51302 onLoad : function() // called on page load...
51306 if (Roo.get('loading')) { // clear any loading indicator..
51307 Roo.get('loading').remove();
51310 //this.switchLang('en'); // set the language to english..
51313 success: function(response, opts) { // check successfull...
51315 var res = this.processResponse(response);
51316 this.checkFails =0;
51317 if (!res.success) { // error!
51318 this.checkFails = 5;
51319 //console.log('call failure');
51320 return this.failure(response,opts);
51323 if (!res.data.id) { // id=0 == login failure.
51324 return this.show();
51328 //console.log(success);
51329 this.fillAuth(res.data);
51330 this.checkFails =0;
51331 Roo.XComponent.build();
51333 failure : this.show
51339 check: function(cfg) // called every so often to refresh cookie etc..
51341 if (cfg.again) { // could be undefined..
51344 this.checkFails = 0;
51347 if (this.sending) {
51348 if ( this.checkFails > 4) {
51349 Roo.MessageBox.alert("Error",
51350 "Error getting authentication status. - try reloading, or wait a while", function() {
51351 _this.sending = false;
51356 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51359 this.sending = true;
51366 method: this.method,
51367 success: cfg.success || this.success,
51368 failure : cfg.failure || this.failure,
51378 window.onbeforeunload = function() { }; // false does not work for IE..
51388 failure : function() {
51389 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51390 document.location = document.location.toString() + '?ts=' + Math.random();
51394 success : function() {
51395 _this.user = false;
51396 this.checkFails =0;
51398 document.location = document.location.toString() + '?ts=' + Math.random();
51405 processResponse : function (response)
51409 res = Roo.decode(response.responseText);
51411 if (typeof(res) != 'object') {
51412 res = { success : false, errorMsg : res, errors : true };
51414 if (typeof(res.success) == 'undefined') {
51415 res.success = false;
51419 res = { success : false, errorMsg : response.responseText, errors : true };
51424 success : function(response, opts) // check successfull...
51426 this.sending = false;
51427 var res = this.processResponse(response);
51428 if (!res.success) {
51429 return this.failure(response, opts);
51431 if (!res.data || !res.data.id) {
51432 return this.failure(response,opts);
51434 //console.log(res);
51435 this.fillAuth(res.data);
51437 this.checkFails =0;
51442 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51444 this.authUser = -1;
51445 this.sending = false;
51446 var res = this.processResponse(response);
51447 //console.log(res);
51448 if ( this.checkFails > 2) {
51450 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51451 "Error getting authentication status. - try reloading");
51454 opts.callCfg.again = true;
51455 this.check.defer(1000, this, [ opts.callCfg ]);
51461 fillAuth: function(au) {
51462 this.startAuthCheck();
51463 this.authUserId = au.id;
51464 this.authUser = au;
51465 this.lastChecked = new Date();
51466 this.fireEvent('refreshed', au);
51467 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
51468 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
51469 au.lang = au.lang || 'en';
51470 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
51471 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
51472 this.switchLang(au.lang );
51475 // open system... - -on setyp..
51476 if (this.authUserId < 0) {
51477 Roo.MessageBox.alert("Warning",
51478 "This is an open system - please set up a admin user with a password.");
51481 //Pman.onload(); // which should do nothing if it's a re-auth result...
51486 startAuthCheck : function() // starter for timeout checking..
51488 if (this.intervalID) { // timer already in place...
51492 this.intervalID = window.setInterval(function() {
51493 _this.check(false);
51494 }, 120000); // every 120 secs = 2mins..
51500 switchLang : function (lang)
51502 _T = typeof(_T) == 'undefined' ? false : _T;
51503 if (!_T || !lang.length) {
51507 if (!_T && lang != 'en') {
51508 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51512 if (typeof(_T.en) == 'undefined') {
51514 Roo.apply(_T.en, _T);
51517 if (typeof(_T[lang]) == 'undefined') {
51518 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51523 Roo.apply(_T, _T[lang]);
51524 // just need to set the text values for everything...
51526 /* this will not work ...
51530 function formLabel(name, val) {
51531 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
51534 formLabel('password', "Password"+':');
51535 formLabel('username', "Email Address"+':');
51536 formLabel('lang', "Language"+':');
51537 this.dialog.setTitle("Login");
51538 this.dialog.buttons[0].setText("Forgot Password");
51539 this.dialog.buttons[1].setText("Login");
51558 collapsible: false,
51560 center: { // needed??
51563 // tabPosition: 'top',
51566 alwaysShowTabs: false
51570 show : function(dlg)
51572 //console.log(this);
51573 this.form = this.layout.getRegion('center').activePanel.form;
51574 this.form.dialog = dlg;
51575 this.buttons[0].form = this.form;
51576 this.buttons[0].dialog = dlg;
51577 this.buttons[1].form = this.form;
51578 this.buttons[1].dialog = dlg;
51580 //this.resizeToLogo.defer(1000,this);
51581 // this is all related to resizing for logos..
51582 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
51584 // this.resizeToLogo.defer(1000,this);
51587 //var w = Ext.lib.Dom.getViewWidth() - 100;
51588 //var h = Ext.lib.Dom.getViewHeight() - 100;
51589 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
51591 if (this.disabled) {
51596 if (this.user.id < 0) { // used for inital setup situations.
51600 if (this.intervalID) {
51601 // remove the timer
51602 window.clearInterval(this.intervalID);
51603 this.intervalID = false;
51607 if (Roo.get('loading')) {
51608 Roo.get('loading').remove();
51610 if (Roo.get('loading-mask')) {
51611 Roo.get('loading-mask').hide();
51614 //incomming._node = tnode;
51616 //this.dialog.modal = !modal;
51617 //this.dialog.show();
51621 this.form.setValues({
51622 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
51623 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
51626 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
51627 if (this.form.findField('username').getValue().length > 0 ){
51628 this.form.findField('password').focus();
51630 this.form.findField('username').focus();
51638 xtype : 'ContentPanel',
51650 style : 'margin: 10px;',
51653 actionfailed : function(f, act) {
51654 // form can return { errors: .... }
51656 //act.result.errors // invalid form element list...
51657 //act.result.errorMsg// invalid form element list...
51659 this.dialog.el.unmask();
51660 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
51661 "Login failed - communication error - try again.");
51664 actioncomplete: function(re, act) {
51666 Roo.state.Manager.set(
51667 this.dialog.realm + '.username',
51668 this.findField('username').getValue()
51670 Roo.state.Manager.set(
51671 this.dialog.realm + '.lang',
51672 this.findField('lang').getValue()
51675 this.dialog.fillAuth(act.result.data);
51677 this.dialog.hide();
51679 if (Roo.get('loading-mask')) {
51680 Roo.get('loading-mask').show();
51682 Roo.XComponent.build();
51690 xtype : 'TextField',
51692 fieldLabel: "Email Address",
51695 autoCreate : {tag: "input", type: "text", size: "20"}
51698 xtype : 'TextField',
51700 fieldLabel: "Password",
51701 inputType: 'password',
51704 autoCreate : {tag: "input", type: "text", size: "20"},
51706 specialkey : function(e,ev) {
51707 if (ev.keyCode == 13) {
51708 this.form.dialog.el.mask("Logging in");
51709 this.form.doAction('submit', {
51710 url: this.form.dialog.url,
51711 method: this.form.dialog.method
51718 xtype : 'ComboBox',
51720 fieldLabel: "Language",
51723 xtype : 'SimpleStore',
51724 fields: ['lang', 'ldisp'],
51726 [ 'en', 'English' ],
51727 [ 'zh_HK' , '\u7E41\u4E2D' ],
51728 [ 'zh_CN', '\u7C21\u4E2D' ]
51732 valueField : 'lang',
51733 hiddenName: 'lang',
51735 displayField:'ldisp',
51739 triggerAction: 'all',
51740 emptyText:'Select a Language...',
51741 selectOnFocus:true,
51743 select : function(cb, rec, ix) {
51744 this.form.switchLang(rec.data.lang);
51760 text : "Forgot Password",
51762 click : function() {
51763 //console.log(this);
51764 var n = this.form.findField('username').getValue();
51766 Roo.MessageBox.alert("Error", "Fill in your email address");
51770 url: this.dialog.url,
51774 method: this.dialog.method,
51775 success: function(response, opts) { // check successfull...
51777 var res = this.dialog.processResponse(response);
51778 if (!res.success) { // error!
51779 Roo.MessageBox.alert("Error" ,
51780 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
51783 Roo.MessageBox.alert("Notice" ,
51784 "Please check you email for the Password Reset message");
51786 failure : function() {
51787 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
51800 click : function () {
51802 this.dialog.el.mask("Logging in");
51803 this.form.doAction('submit', {
51804 url: this.dialog.url,
51805 method: this.dialog.method